From f3c99841f9afa3b2cc43012e200791d42ef73f41 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Wed, 14 Jan 2015 16:35:00 -0500 Subject: [PATCH 01/72] 8067982: Some jcmd /gc/heap_dump tests failed: hprof output contains warning or error Include shared symbols in SymbolTable::symbols_do(SymbolClosure). Reviewed-by: minqi, farvidsson, coleenp --- .../share/vm/classfile/compactHashtable.cpp | 26 ++++++++++++++++++- .../share/vm/classfile/compactHashtable.hpp | 5 +++- .../src/share/vm/classfile/symbolTable.cpp | 6 ++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/classfile/compactHashtable.cpp b/hotspot/src/share/vm/classfile/compactHashtable.cpp index 157b1681425..bd197554293 100644 --- a/hotspot/src/share/vm/classfile/compactHashtable.cpp +++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -221,6 +221,30 @@ template const char* CompactHashtable::init(const char* return (const char*)end; } +template void CompactHashtable::symbols_do(SymbolClosure *cl) { + assert(!DumpSharedSpaces, "run-time only"); + for (juint i = 0; i < _bucket_count; i ++) { + juint bucket_info = _buckets[i]; + juint bucket_offset = BUCKET_OFFSET(bucket_info); + int bucket_type = BUCKET_TYPE(bucket_info); + juint* bucket = _buckets + bucket_offset; + juint* bucket_end = _buckets; + + Symbol* sym; + if (bucket_type == COMPACT_BUCKET_TYPE) { + sym = (Symbol*)((void*)(_base_address + bucket[0])); + cl->do_symbol(&sym); + } else { + bucket_end += BUCKET_OFFSET(_buckets[i + 1]); + while (bucket < bucket_end) { + sym = (Symbol*)((void*)(_base_address + bucket[1])); + cl->do_symbol(&sym); + bucket += 2; + } + } + } +} + // Explicitly instantiate these types template class CompactHashtable; diff --git a/hotspot/src/share/vm/classfile/compactHashtable.hpp b/hotspot/src/share/vm/classfile/compactHashtable.hpp index ac01fa7114b..3e32fc07df9 100644 --- a/hotspot/src/share/vm/classfile/compactHashtable.hpp +++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -249,6 +249,9 @@ public: } return NULL; } + + // iterate over symbols + void symbols_do(SymbolClosure *cl); }; //////////////////////////////////////////////////////////////////////// diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index 4df696f74c7..3d08364be82 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -82,6 +82,10 @@ void SymbolTable::initialize_symbols(int arena_alloc_size) { // Call function for all symbols in the symbol table. void SymbolTable::symbols_do(SymbolClosure *cl) { + // all symbols from shared table + _shared_table.symbols_do(cl); + + // all symbols from the dynamic table const int n = the_table()->table_size(); for (int i = 0; i < n; i++) { for (HashtableEntry* p = the_table()->bucket(i); From dd5f249290582bed676ec952907726e65562449e Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Wed, 7 Jan 2015 08:37:49 +0100 Subject: [PATCH 02/72] 8068503: ppc64: Encode/Decode nodes for disjoint cOops mode Reviewed-by: simonis --- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp | 11 +- .../cpu/ppc/vm/macroAssembler_ppc.inline.hpp | 41 +++-- hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp | 38 ++-- hotspot/src/cpu/ppc/vm/ppc.ad | 167 +++++++++++++++--- 4 files changed, 192 insertions(+), 65 deletions(-) diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index 5c118981415..46216782c97 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -567,16 +567,21 @@ class MacroAssembler: public Assembler { inline void load_with_trap_null_check(Register d, int si16, Register s1); // Load heap oop and decompress. Loaded oop may not be null. - inline void load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1 = noreg); + // Specify tmp to save one cycle. + inline void load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1 = noreg, + Register tmp = noreg); + // Store heap oop and decompress. Decompressed oop may not be null. + // Specify tmp register if d should not be changed. inline void store_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, - /*specify if d must stay uncompressed*/ Register tmp = noreg); + Register tmp = noreg); // Null allowed. inline void load_heap_oop(Register d, RegisterOrConstant offs, Register s1 = noreg); // Encode/decode heap oop. Oop may not be null, else en/decoding goes wrong. + // src == d allowed. inline Register encode_heap_oop_not_null(Register d, Register src = noreg); - inline void decode_heap_oop_not_null(Register d); + inline Register decode_heap_oop_not_null(Register d, Register src = noreg); // Null allowed. inline void decode_heap_oop(Register d); diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp index 84485d4f6af..f5d19dff066 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp @@ -311,11 +311,14 @@ inline void MacroAssembler::load_with_trap_null_check(Register d, int si16, Regi ld(d, si16, s1); } -inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1) { +inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, Register tmp) { if (UseCompressedOops) { - lwz(d, offs, s1); + // In disjoint mode decoding can save a cycle if src != dst. + Register narrowOop = (tmp != noreg && Universe::narrow_oop_base_disjoint()) ? tmp : d; + lwz(narrowOop, offs, s1); // Attention: no null check here! - decode_heap_oop_not_null(d); + Register res = decode_heap_oop_not_null(d, narrowOop); + assert(res == d, "caller will not consume loaded value"); } else { ld(d, offs, s1); } @@ -340,26 +343,36 @@ inline void MacroAssembler::load_heap_oop(Register d, RegisterOrConstant offs, R } inline Register MacroAssembler::encode_heap_oop_not_null(Register d, Register src) { - Register current = (src!=noreg) ? src : d; // Compressed oop is in d if no src provided. - if (Universe::narrow_oop_base() != NULL) { + Register current = (src != noreg) ? src : d; // Oop to be compressed is in d if no src provided. + if (Universe::narrow_oop_base_overlaps()) { sub(d, current, R30); current = d; } if (Universe::narrow_oop_shift() != 0) { - srdi(d, current, LogMinObjAlignmentInBytes); + rldicl(d, current, 64-Universe::narrow_oop_shift(), 32); // Clears the upper bits. current = d; } return current; // Encoded oop is in this register. } -inline void MacroAssembler::decode_heap_oop_not_null(Register d) { +inline Register MacroAssembler::decode_heap_oop_not_null(Register d, Register src) { + if (Universe::narrow_oop_base_disjoint() && src != noreg && src != d && + Universe::narrow_oop_shift() != 0) { + mr(d, R30); + rldimi(d, src, Universe::narrow_oop_shift(), 32-Universe::narrow_oop_shift()); + return d; + } + + Register current = (src != noreg) ? src : d; // Compressed oop is in d if no src provided. if (Universe::narrow_oop_shift() != 0) { - assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); - sldi(d, d, LogMinObjAlignmentInBytes); + sldi(d, current, Universe::narrow_oop_shift()); + current = d; } if (Universe::narrow_oop_base() != NULL) { - add(d, d, R30); + add(d, current, R30); + current = d; } + return current; // Decoded oop is in this register. } inline void MacroAssembler::decode_heap_oop(Register d) { @@ -368,13 +381,7 @@ inline void MacroAssembler::decode_heap_oop(Register d) { cmpwi(CCR0, d, 0); beq(CCR0, isNull); } - if (Universe::narrow_oop_shift() != 0) { - assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); - sldi(d, d, LogMinObjAlignmentInBytes); - } - if (Universe::narrow_oop_base() != NULL) { - add(d, d, R30); - } + decode_heap_oop_not_null(d); bind(isNull); } diff --git a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp index 89c0344a5fe..88e0dec0709 100644 --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp @@ -172,15 +172,15 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, // Load the invoker, as MH -> MH.form -> LF.vmentry __ verify_oop(recv); - __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes()), recv); + __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes()), recv, temp2); __ verify_oop(method_temp); - __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()), method_temp); + __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()), method_temp, temp2); __ verify_oop(method_temp); - // the following assumes that a Method* is normally compressed in the vmtarget field: + // The following assumes that a Method* is normally compressed in the vmtarget field: __ ld(method_temp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()), method_temp); if (VerifyMethodHandles && !for_compiler_entry) { - // make sure recv is already on stack + // Make sure recv is already on stack. __ ld(temp2, in_bytes(Method::const_offset()), method_temp); __ load_sized_value(temp2, in_bytes(ConstMethod::size_of_parameters_offset()), temp2, sizeof(u2), /*is_signed*/ false); @@ -259,8 +259,9 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* } if (TraceMethodHandles) { - if (tmp_mh != noreg) + if (tmp_mh != noreg) { __ mr(R23_method_handle, tmp_mh); // make stub happy + } trace_method_handle_interpreter_entry(_masm, iid); } @@ -332,7 +333,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) { Label L_ok; Register temp2_defc = temp2; - __ load_heap_oop_not_null(temp2_defc, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg); + __ load_heap_oop_not_null(temp2_defc, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg, temp3); load_klass_from_Class(_masm, temp2_defc, temp3, temp4); __ verify_klass_ptr(temp2_defc); __ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, temp4, L_ok); @@ -407,7 +408,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, } Register temp2_intf = temp2; - __ load_heap_oop_not_null(temp2_intf, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg); + __ load_heap_oop_not_null(temp2_intf, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg, temp3); load_klass_from_Class(_masm, temp2_intf, temp3, temp4); __ verify_klass_ptr(temp2_intf); @@ -464,7 +465,7 @@ void trace_method_handle_stub(const char* adaptername, strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH const char* mh_reg_name = has_mh ? "R23_method_handle" : "G23"; tty->print_cr("MH %s %s="INTPTR_FORMAT " sp=" INTPTR_FORMAT, - adaptername, mh_reg_name, (intptr_t) mh, (intptr_t) entry_sp); + adaptername, mh_reg_name, (intptr_t) mh, entry_sp); if (Verbose) { tty->print_cr("Registers:"); @@ -535,23 +536,22 @@ void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adapt BLOCK_COMMENT("trace_method_handle {"); - int nbytes_save = 10 * 8; // 10 volatile gprs - __ save_LR_CR(R0); - __ mr(R0, R1_SP); // saved_sp - assert(Assembler::is_simm(-nbytes_save, 16), "Overwriting R0"); - // Push_frame_reg_args only uses R0 if nbytes_save is wider than 16 bit. - __ push_frame_reg_args(nbytes_save, R0); - __ save_volatile_gprs(R1_SP, frame::abi_reg_args_size); // Except R0. + const Register tmp = R11; // Will be preserved. + const int nbytes_save = 11*8; // volatile gprs except R0 + __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ save_LR_CR(tmp); // save in old frame - __ load_const(R3_ARG1, (address)adaptername); + __ mr(R5_ARG3, R1_SP); // saved_sp + __ push_frame_reg_args(nbytes_save, tmp); + + __ load_const_optimized(R3_ARG1, (address)adaptername, tmp); __ mr(R4_ARG2, R23_method_handle); - __ mr(R5_ARG3, R0); // saved_sp __ mr(R6_ARG4, R1_SP); __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub)); - __ restore_volatile_gprs(R1_SP, 112); // Except R0. __ pop_frame(); - __ restore_LR_CR(R0); + __ restore_LR_CR(tmp); + __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 BLOCK_COMMENT("} trace_method_handle"); } diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index 51a9762e983..a9d576c5014 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -1,6 +1,6 @@ // -// Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. -// Copyright 2012, 2014 SAP AG. All rights reserved. +// Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +// Copyright 2012, 2015 SAP AG. 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 @@ -2698,7 +2698,7 @@ encode %{ const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else if (constant_reloc == relocInfo::metadata_type) { - AddressLiteral a = __ allocate_metadata_address((Metadata *)val); + AddressLiteral a = __ constant_metadata_address((Metadata *)val); const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else { @@ -2727,7 +2727,7 @@ encode %{ const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else if (constant_reloc == relocInfo::metadata_type) { - AddressLiteral a = __ allocate_metadata_address((Metadata *)val); + AddressLiteral a = __ constant_metadata_address((Metadata *)val); const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else { // non-oop pointers, e.g. card mark base, heap top @@ -6029,6 +6029,20 @@ instruct clearMs32b(iRegNdst dst, iRegNsrc src) %{ ins_pipe(pipe_class_default); %} +// Optimize DecodeN for disjoint base. +// Load base of compressed oops into a register +instruct loadBase(iRegLdst dst) %{ + effect(DEF dst); + + format %{ "MR $dst, r30_heapbase" %} + size(4); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_or); + __ mr($dst$$Register, R30); + %} + ins_pipe(pipe_class_default); +%} + // Loading ConN must be postalloc expanded so that edges between // the nodes are safe. They may not interfere with a safepoint. // GL TODO: This needs three instructions: better put this into the constant pool. @@ -6724,13 +6738,12 @@ instruct cond_set_0_oop(iRegNdst dst, flagsReg crx, iRegPsrc src1) %{ ins_pipe(pipe_class_default); %} -// base != 0 -// 32G aligned narrow oop base. -instruct encodeP_32GAligned(iRegNdst dst, iRegPsrc src) %{ +// Disjoint narrow oop base. +instruct encodeP_Disjoint(iRegNdst dst, iRegPsrc src) %{ match(Set dst (EncodeP src)); - predicate(false /* TODO: PPC port Universe::narrow_oop_base_disjoint()*/); + predicate(Universe::narrow_oop_base_disjoint()); - format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with 32G aligned base" %} + format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with disjoint base" %} size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_rldicl); @@ -6745,7 +6758,7 @@ instruct encodeP_Ex(iRegNdst dst, flagsReg crx, iRegPsrc src) %{ effect(TEMP crx); predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull && Universe::narrow_oop_shift() != 0 && - true /* TODO: PPC port Universe::narrow_oop_base_overlaps()*/); + Universe::narrow_oop_base_overlaps()); format %{ "EncodeP $dst, $crx, $src \t// postalloc expanded" %} postalloc_expand( postalloc_expand_encode_oop(dst, src, crx)); @@ -6756,7 +6769,7 @@ instruct encodeP_not_null_Ex(iRegNdst dst, iRegPsrc src) %{ match(Set dst (EncodeP src)); predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull && Universe::narrow_oop_shift() != 0 && - true /* TODO: PPC port Universe::narrow_oop_base_overlaps()*/); + Universe::narrow_oop_base_overlaps()); format %{ "EncodeP $dst, $src\t// $src != Null, postalloc expanded" %} postalloc_expand( postalloc_expand_encode_oop_not_null(dst, src) ); @@ -6876,6 +6889,7 @@ instruct decodeN_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{ n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant) && Universe::narrow_oop_shift() != 0 && Universe::narrow_oop_base() != 0); + ins_cost(4 * DEFAULT_COST); // Should be more expensive than decodeN_Disjoint_isel_Ex. effect(TEMP crx); format %{ "DecodeN $dst, $src \t// Kills $crx, postalloc expanded" %} @@ -6897,6 +6911,106 @@ instruct decodeN_nullBase(iRegPdst dst, iRegNsrc src) %{ ins_pipe(pipe_class_default); %} +// Optimize DecodeN for disjoint base. +// Shift narrow oop and or it into register that already contains the heap base. +// Base == dst must hold, and is assured by construction in postaloc_expand. +instruct decodeN_mergeDisjoint(iRegPdst dst, iRegNsrc src, iRegLsrc base) %{ + match(Set dst (DecodeN src)); + effect(TEMP base); + predicate(false); + + format %{ "RLDIMI $dst, $src, shift, 32-shift \t// DecodeN (disjoint base)" %} + size(4); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_rldimi); + __ rldimi($dst$$Register, $src$$Register, Universe::narrow_oop_shift(), 32-Universe::narrow_oop_shift()); + %} + ins_pipe(pipe_class_default); +%} + +// Optimize DecodeN for disjoint base. +// This node requires only one cycle on the critical path. +// We must postalloc_expand as we can not express use_def effects where +// the used register is L and the def'ed register P. +instruct decodeN_Disjoint_notNull_Ex(iRegPdst dst, iRegNsrc src) %{ + match(Set dst (DecodeN src)); + effect(TEMP_DEF dst); + predicate((n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull || + n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) && + Universe::narrow_oop_base_disjoint()); + ins_cost(DEFAULT_COST); + + format %{ "MOV $dst, R30 \t\n" + "RLDIMI $dst, $src, shift, 32-shift \t// decode with disjoint base" %} + postalloc_expand %{ + loadBaseNode *n1 = new loadBaseNode(); + n1->add_req(NULL); + n1->_opnds[0] = op_dst; + + decodeN_mergeDisjointNode *n2 = new decodeN_mergeDisjointNode(); + n2->add_req(n_region, n_src, n1); + n2->_opnds[0] = op_dst; + n2->_opnds[1] = op_src; + n2->_opnds[2] = op_dst; + n2->_bottom_type = _bottom_type; + + ra_->set_pair(n1->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n2->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + + nodes->push(n1); + nodes->push(n2); + %} +%} + +instruct decodeN_Disjoint_isel_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{ + match(Set dst (DecodeN src)); + effect(TEMP_DEF dst, TEMP crx); + predicate((n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull && + n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant) && + Universe::narrow_oop_base_disjoint() && VM_Version::has_isel()); + ins_cost(3 * DEFAULT_COST); + + format %{ "DecodeN $dst, $src \t// decode with disjoint base using isel" %} + postalloc_expand %{ + loadBaseNode *n1 = new loadBaseNode(); + n1->add_req(NULL); + n1->_opnds[0] = op_dst; + + cmpN_reg_imm0Node *n_compare = new cmpN_reg_imm0Node(); + n_compare->add_req(n_region, n_src); + n_compare->_opnds[0] = op_crx; + n_compare->_opnds[1] = op_src; + n_compare->_opnds[2] = new immN_0Oper(TypeNarrowOop::NULL_PTR); + + decodeN_mergeDisjointNode *n2 = new decodeN_mergeDisjointNode(); + n2->add_req(n_region, n_src, n1); + n2->_opnds[0] = op_dst; + n2->_opnds[1] = op_src; + n2->_opnds[2] = op_dst; + n2->_bottom_type = _bottom_type; + + cond_set_0_ptrNode *n_cond_set = new cond_set_0_ptrNode(); + n_cond_set->add_req(n_region, n_compare, n2); + n_cond_set->_opnds[0] = op_dst; + n_cond_set->_opnds[1] = op_crx; + n_cond_set->_opnds[2] = op_dst; + n_cond_set->_bottom_type = _bottom_type; + + assert(ra_->is_oop(this) == true, "A decodeN node must produce an oop!"); + ra_->set_oop(n_cond_set, true); + + ra_->set_pair(n1->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n_compare->_idx, ra_->get_reg_second(n_crx), ra_->get_reg_first(n_crx)); + ra_->set_pair(n2->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n_cond_set->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + + nodes->push(n1); + nodes->push(n_compare); + nodes->push(n2); + nodes->push(n_cond_set); + %} +%} + // src != 0, shift != 0, base != 0 instruct decodeN_notNull_addBase_Ex(iRegPdst dst, iRegNsrc src) %{ match(Set dst (DecodeN src)); @@ -6904,6 +7018,7 @@ instruct decodeN_notNull_addBase_Ex(iRegPdst dst, iRegNsrc src) %{ n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) && Universe::narrow_oop_shift() != 0 && Universe::narrow_oop_base() != 0); + ins_cost(2 * DEFAULT_COST); format %{ "DecodeN $dst, $src \t// $src != NULL, postalloc expanded" %} postalloc_expand( postalloc_expand_decode_oop_not_null(dst, src)); @@ -6973,13 +7088,12 @@ instruct encodePKlass_sub_base(iRegPdst dst, iRegLsrc base, iRegPdst src) %{ ins_pipe(pipe_class_default); %} -// base != 0 -// 32G aligned narrow oop base. -instruct encodePKlass_32GAligned(iRegNdst dst, iRegPsrc src) %{ +// Disjoint narrow oop base. +instruct encodePKlass_Disjoint(iRegNdst dst, iRegPsrc src) %{ match(Set dst (EncodePKlass src)); predicate(false /* TODO: PPC port Universe::narrow_klass_base_disjoint()*/); - format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with 32G aligned base" %} + format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with disjoint base" %} size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_rldicl); @@ -7486,7 +7600,7 @@ instruct storeLConditional_regP_regL_regL(flagsReg crx, indirect mem_ptr, iRegLs ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_compound); __ cmpxchgd($crx$$CondRegister, R0, $oldVal$$Register, $newVal$$Register, $mem_ptr$$Register, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + MacroAssembler::MemBarAcq, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, NULL, true); %} ins_pipe(pipe_class_default); @@ -10476,7 +10590,7 @@ instruct cmpN_reg_reg(flagsReg crx, iRegNsrc src1, iRegNsrc src2) %{ match(Set crx (CmpN src1 src2)); size(4); - ins_cost(DEFAULT_COST); + ins_cost(2); format %{ "CMPLW $crx, $src1, $src2 \t// compressed ptr" %} ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_cmpl); @@ -10488,7 +10602,7 @@ instruct cmpN_reg_reg(flagsReg crx, iRegNsrc src1, iRegNsrc src2) %{ instruct cmpN_reg_imm0(flagsReg crx, iRegNsrc src1, immN_0 src2) %{ match(Set crx (CmpN src1 src2)); // Make this more expensive than zeroCheckN_iReg_imm0. - ins_cost(DEFAULT_COST); + ins_cost(2); format %{ "CMPLWI $crx, $src1, $src2 \t// compressed ptr" %} size(4); @@ -10508,6 +10622,7 @@ instruct zeroCheckP_reg_imm0(cmpOp cmp, iRegP_N2P value, immP_0 zero, label labl _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne && _leaf->as_If()->_prob >= PROB_LIKELY_MAG(4) && Matcher::branches_to_uncommon_trap(_leaf)); + ins_cost(1); // Should not be cheaper than zeroCheckN. ins_is_TrapBasedCheckNode(true); @@ -10889,7 +11004,7 @@ instruct branchLoopEndSched(cmpOp cmp, flagsReg crx, label labl) %{ instruct partialSubtypeCheck(iRegPdst result, iRegP_N2P subklass, iRegP_N2P superklass, iRegPdst tmp_klass, iRegPdst tmp_arrayptr) %{ match(Set result (PartialSubtypeCheck subklass superklass)); - effect(TEMP result, TEMP tmp_klass, TEMP tmp_arrayptr); + effect(TEMP_DEF result, TEMP tmp_klass, TEMP tmp_arrayptr); ins_cost(DEFAULT_COST*10); format %{ "PartialSubtypeCheck $result = ($subklass instanceOf $superklass) tmp: $tmp_klass, $tmp_arrayptr" %} @@ -11000,7 +11115,7 @@ instruct string_indexOf_imm1_char(iRegIdst result, iRegPsrc haystack, iRegIsrc h predicate(SpecialStringIndexOf); // type check implicit by parameter type, See Matcher::match_rule_supported match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); - effect(TEMP result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1); ins_cost(150); format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" @@ -11037,7 +11152,7 @@ instruct string_indexOf_imm1(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt iRegIdst tmp1, iRegIdst tmp2, flagsRegCR0 cr0, flagsRegCR1 cr1) %{ match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); - effect(USE_KILL needle, /* TDEF needle, */ TEMP result, + effect(USE_KILL needle, /* TDEF needle, */ TEMP_DEF result, TEMP tmp1, TEMP tmp2); // Required for EA: check if it is still a type_array. predicate(SpecialStringIndexOf && n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && @@ -11084,7 +11199,7 @@ instruct string_indexOf_imm(iRegIdst result, iRegPsrc haystack, rscratch1RegI ha iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6) %{ match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); - effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP result, + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6); // Required for EA: check if it is still a type_array. predicate(SpecialStringIndexOf && n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && @@ -11118,7 +11233,7 @@ instruct string_indexOf(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6) %{ match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ - TEMP result, + TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6); predicate(SpecialStringIndexOf); // See Matcher::match_rule_supported. ins_cost(300); @@ -11142,7 +11257,7 @@ instruct string_equals_imm(iRegPsrc str1, iRegPsrc str2, uimmI15 cntImm, iRegIds iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0, flagsRegCR6 cr6, regCTR ctr) %{ match(Set result (StrEquals (Binary str1 str2) cntImm)); - effect(TEMP result, TEMP tmp1, TEMP tmp2, + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr6, KILL ctr); predicate(SpecialStringEquals); // See Matcher::match_rule_supported. ins_cost(250); @@ -11165,7 +11280,7 @@ instruct string_equals(iRegPsrc str1, iRegPsrc str2, iRegIsrc cnt, iRegIdst resu iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, iRegPdst tmp4, iRegPdst tmp5, flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(TEMP result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); predicate(SpecialStringEquals); // See Matcher::match_rule_supported. ins_cost(300); @@ -11188,7 +11303,7 @@ instruct string_equals(iRegPsrc str1, iRegPsrc str2, iRegIsrc cnt, iRegIdst resu instruct string_compare(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, iRegPdst tmp, flagsRegCR0 cr0, regCTR ctr) %{ match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(USE_KILL cnt1, USE_KILL cnt2, USE_KILL str1, USE_KILL str2, TEMP result, TEMP tmp, KILL cr0, KILL ctr); + effect(USE_KILL cnt1, USE_KILL cnt2, USE_KILL str1, USE_KILL str2, TEMP_DEF result, TEMP tmp, KILL cr0, KILL ctr); ins_cost(300); ins_alignment(8); // 'compute_padding()' gets called, up to this number-1 nops will get inserted. From 21cd501d2740c0c9b5a6819ac2262cdffc260d38 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 13 Jan 2015 16:09:52 +0100 Subject: [PATCH 03/72] 8069590: AIX port of "8050807: Better performing performance data handling" Co-authored-by: Martin Doerr Reviewed-by: simonis, goetz --- hotspot/make/aix/makefiles/xlc.make | 6 + hotspot/src/os/aix/vm/perfMemory_aix.cpp | 482 +++++++++++++++++++---- 2 files changed, 404 insertions(+), 84 deletions(-) diff --git a/hotspot/make/aix/makefiles/xlc.make b/hotspot/make/aix/makefiles/xlc.make index b6525327528..17a71b60124 100644 --- a/hotspot/make/aix/makefiles/xlc.make +++ b/hotspot/make/aix/makefiles/xlc.make @@ -74,6 +74,12 @@ CFLAGS += -D_REENTRANT # no xlc counterpart for -fcheck-new # CFLAGS += -fcheck-new +# We need to define this on the command line if we want to use the the +# predefined format specifiers from "inttypes.h". Otherwise system headrs +# can indirectly include inttypes.h before we define __STDC_FORMAT_MACROS +# in globalDefinitions.hpp +CFLAGS += -D__STDC_FORMAT_MACROS + ARCHFLAG = -q64 CFLAGS += $(ARCHFLAG) diff --git a/hotspot/src/os/aix/vm/perfMemory_aix.cpp b/hotspot/src/os/aix/vm/perfMemory_aix.cpp index b509cf94110..c9dd76b7881 100644 --- a/hotspot/src/os/aix/vm/perfMemory_aix.cpp +++ b/hotspot/src/os/aix/vm/perfMemory_aix.cpp @@ -31,6 +31,7 @@ #include "os_aix.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/perfMemory.hpp" +#include "services/memTracker.hpp" #include "utilities/exceptions.hpp" // put OS-includes here @@ -196,12 +197,37 @@ static pid_t filename_to_pid(const char* filename) { return pid; } +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + return false; + } + return true; +} -// check if the given path is considered a secure directory for + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. -// static bool is_directory_secure(const char* path) { struct stat statbuf; int result = 0; @@ -211,38 +237,276 @@ static bool is_directory_secure(const char* path) { return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + +// (Taken over from Solaris to support the O_NOFOLLOW case on AIX.) +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { + return false; + } +} + +// Helper functions for open without O_NOFOLLOW which is not present on AIX 5.3/6.1. +// We use the jdk6 implementation here. +#ifndef O_NOFOLLOW +// The O_NOFOLLOW oflag doesn't exist before solaris 5.10, this is to simulate that behaviour +// was done in jdk 5/6 hotspot by Oracle this way +static int open_o_nofollow_impl(const char* path, int oflag, mode_t mode, bool use_mode) { + struct stat orig_st; + struct stat new_st; + bool create; + int error; + int fd; + + create = false; + + if (lstat(path, &orig_st) != 0) { + if (errno == ENOENT && (oflag & O_CREAT) != 0) { + // File doesn't exist, but_we want to create it, add O_EXCL flag + // to make sure no-one creates it (or a symlink) before us + // This works as we expect with symlinks, from posix man page: + // 'If O_EXCL and O_CREAT are set, and path names a symbolic + // link, open() shall fail and set errno to [EEXIST]'. + oflag |= O_EXCL; + create = true; + } else { + // File doesn't exist, and we are not creating it. + return OS_ERR; } + } else { + // Lstat success, check if existing file is a link. + if ((orig_st.st_mode & S_IFMT) == S_IFLNK) { + // File is a symlink. + errno = ELOOP; + return OS_ERR; + } + } + + if (use_mode == true) { + fd = open(path, oflag, mode); + } else { + fd = open(path, oflag); + } + + if (fd == OS_ERR) { + return fd; + } + + // Can't do inode checks on before/after if we created the file. + if (create == false) { + if (fstat(fd, &new_st) != 0) { + // Keep errno from fstat, in case close also fails. + error = errno; + ::close(fd); + errno = error; + return OS_ERR; + } + + if (orig_st.st_dev != new_st.st_dev || orig_st.st_ino != new_st.st_ino) { + // File was tampered with during race window. + ::close(fd); + errno = EEXIST; + if (PrintMiscellaneous && Verbose) { + warning("possible file tampering attempt detected when opening %s", path); + } + return OS_ERR; + } + } + + return fd; +} + +static int open_o_nofollow(const char* path, int oflag, mode_t mode) { + return open_o_nofollow_impl(path, oflag, mode, true); +} + +static int open_o_nofollow(const char* path, int oflag) { + return open_o_nofollow_impl(path, oflag, 0, false); +} +#endif + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + + // No O_NOFOLLOW defined at buildtime, and it is not documented for open; + // so provide a workaround in this case. +#ifdef O_NOFOLLOW + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); +#else + // workaround (jdk6 coding) + RESTARTABLE(::open_o_nofollow(dirname, O_RDONLY), result); +#endif + + if (result == OS_ERR) { + // Directory doesn't exist or is a symlink, so there is nothing to cleanup. + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } + } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirp->dd_fd)) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirp->dd_fd; + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } - -// return the user name for the given user id -// -// the caller is expected to free the allocated memory. +// Return the user name for the given user id. // +// The caller is expected to free the allocated memory. static char* get_user_name(uid_t uid) { struct passwd pwent; - // determine the max pwbuf size from sysconf, and hardcode + // Determine the max pwbuf size from sysconf, and hardcode // a default if this not available through sysconf. - // long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (bufsize == -1) bufsize = 1024; @@ -344,7 +608,8 @@ static char* get_user_name_slow(int vmid, TRAPS) { strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // Open the user directory. + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name); @@ -464,28 +729,7 @@ static void remove_file(const char* path) { } } - -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path); -} - - -// cleanup stale shared memory resources +// Cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in // the named user temporary directory. It scans the named directory @@ -493,33 +737,26 @@ static void remove_file(const char* dirname, const char* filename) { // process id is extracted from the file name and a test is run to // determine if the process is alive. If the process is not alive, // any stale file resources are removed. -// static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // Open the directory. + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup + // Directory doesn't exist or is insecure, so there is nothing to cleanup. return; } - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory - os::closedir(dirp); - return; - } - - // for each entry in the directory that matches the expected file + // For each entry in the directory that matches the expected file // name pattern, determine if the file resources are stale and if // so, remove the file resources. Note, instrumented HotSpot processes // for this user may start and/or terminate during this search and // remove or create new files in this directory. The behavior of this // loop under these conditions is dependent upon the implementation of // opendir/readdir. - // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -529,56 +766,55 @@ static void cleanup_sharedmem_resources(const char* dirname) { if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { - // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + // Attempt to remove all unexpected files, except "." and "..". + unlink(entry->d_name); } errno = 0; continue; } - // we now have a file name that converts to a valid integer + // We now have a file name that converts to a valid integer // that could represent a process id . if this process id // matches the current process id or the process is not running, // then remove the stale file resources. // - // process liveness is detected by sending signal number 0 to + // Process liveness is detected by sending signal number 0 to // the process id (see kill(2)). if kill determines that the // process does not exist, then the file resources are removed. // if kill determines that that we don't have permission to // signal the process, then the file resources are assumed to // be stale and are removed because the resources for such a // process should be in a different user specific directory. - // if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); - FREE_C_HEAP_ARRAY(char, dbuf); + + // Close the directory and reset the current working directory. + close_directory_secure_cwd(dirp, saved_cwd_fd); + + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); } -// make the user specific temporary directory. Returns true if +// Make the user specific temporary directory. Returns true if // the directory exists and is secure upon return. Returns false // if the directory exists but is either a symlink, is otherwise // insecure, or if an error occurred. -// static bool make_user_tmp_dir(const char* dirname) { - // create the directory with 0755 permissions. note that the directory + // Create the directory with 0755 permissions. note that the directory // will be owned by euid::egid, which may not be the same as uid::gid. - // if (mkdir(dirname, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == OS_ERR) { if (errno == EEXIST) { // The directory already exists and was probably created by another // JVM instance. However, this could also be the result of a // deliberate symlink. Verify that the existing directory is safe. - // if (!is_directory_secure(dirname)) { - // directory is not secure + // Directory is not secure. if (PrintMiscellaneous && Verbose) { warning("%s directory is insecure\n", dirname); } @@ -614,19 +850,63 @@ static int create_sharedmem_resources(const char* dirname, const char* filename, return -1; } - int result; - - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); - } + int saved_cwd_fd; + // Open the directory and set the current working directory to it. + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. return -1; } + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. + int result; + + // No O_NOFOLLOW defined at buildtime, and it is not documented for open; + // so provide a workaround in this case. +#ifdef O_NOFOLLOW + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); +#else + // workaround function (jdk6 code) + RESTARTABLE(::open_o_nofollow(filename, O_RDWR|O_CREAT, S_IREAD|S_IWRITE), result); +#endif + + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } + } + // Close the directory and reset the current working directory. + close_directory_secure_cwd(dirp, saved_cwd_fd); + + return -1; + } + // Close the directory and reset the current working directory. + close_directory_secure_cwd(dirp, saved_cwd_fd); + // save the file descriptor int fd = result; + // Check to see if the file is secure. + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // Truncate the file to get rid of any existing data. + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -648,7 +928,14 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { // open the file int result; + // No O_NOFOLLOW defined at buildtime, and it is not documented for open; + // so provide a workaround in this case +#ifdef O_NOFOLLOW RESTARTABLE(::open(filename, oflags), result); +#else + RESTARTABLE(::open_o_nofollow(filename, oflags), result); +#endif + if (result == OS_ERR) { if (errno == ENOENT) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), @@ -662,8 +949,15 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); } } + int fd = result; - return result; + // Check to see if the file is secure. + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -695,13 +989,21 @@ static char* mmap_create_shared(size_t size) { char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // Get the short filename. + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } + // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name); FREE_C_HEAP_ARRAY(char, dirname); @@ -733,6 +1035,9 @@ static char* mmap_create_shared(size_t size) { // clear the shared memory region (void)::memset((void*) mapAddress, 0, size); + // It does not go through os api, the operation has to record from here. + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC, mtInternal); + return mapAddress; } @@ -807,7 +1112,7 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor char* mapAddress; int result; int fd; - size_t size; + size_t size = 0; const char* luser = NULL; int mmap_prot; @@ -819,12 +1124,18 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; + + // No O_NOFOLLOW defined at buildtime, and it is not documented for open. +#ifdef O_NOFOLLOW + file_flags = O_RDONLY | O_NOFOLLOW; +#else file_flags = O_RDONLY; +#endif } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode"); @@ -853,9 +1164,9 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor // store file, we don't follow them when attaching either. // if (!is_directory_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname); + FREE_C_HEAP_ARRAY(char, dirname, mtInternal); if (luser != user) { - FREE_C_HEAP_ARRAY(char, luser); + FREE_C_HEAP_ARRAY(char, luser, mtInternal); } THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Process not found"); @@ -901,6 +1212,9 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor "Could not map PerfMemory"); } + // It does not go through os api, the operation has to record from here. + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC, mtInternal); + *addr = mapAddress; *sizep = size; From 4e980350cab599cd93d4f3eacb8ebdd7aecb5db4 Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Wed, 14 Jan 2015 08:14:23 -0500 Subject: [PATCH 04/72] 8055146: Split Verifier incorrectly throws VerifyError for getstatic of an array field Allow fieldClass for getstatic and putstatic to be an array Reviewed-by: dholmes, acorn --- hotspot/src/share/vm/classfile/verifier.cpp | 14 ++++++++++---- hotspot/src/share/vm/classfile/verifier.hpp | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp index 679d70de021..d08a818ae65 100644 --- a/hotspot/src/share/vm/classfile/verifier.cpp +++ b/hotspot/src/share/vm/classfile/verifier.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, 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 @@ -1546,10 +1546,15 @@ void ClassVerifier::verify_method(methodHandle m, TRAPS) { no_control_flow = true; break; case Bytecodes::_getstatic : case Bytecodes::_putstatic : + // pass TRUE, operand can be an array type for getstatic/putstatic. + verify_field_instructions( + &bcs, ¤t_frame, cp, true, CHECK_VERIFY(this)); + no_control_flow = false; break; case Bytecodes::_getfield : case Bytecodes::_putfield : + // pass FALSE, operand can't be an array type for getfield/putfield. verify_field_instructions( - &bcs, ¤t_frame, cp, CHECK_VERIFY(this)); + &bcs, ¤t_frame, cp, false, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_invokevirtual : case Bytecodes::_invokespecial : @@ -2107,6 +2112,7 @@ bool ClassVerifier::name_in_supers( void ClassVerifier::verify_field_instructions(RawBytecodeStream* bcs, StackMapFrame* current_frame, constantPoolHandle cp, + bool allow_arrays, TRAPS) { u2 index = bcs->get_index_u2(); verify_cp_type(bcs->bci(), index, cp, @@ -2126,8 +2132,8 @@ void ClassVerifier::verify_field_instructions(RawBytecodeStream* bcs, // Get referenced class type VerificationType ref_class_type = cp_ref_index_to_type( index, cp, CHECK_VERIFY(this)); - if (!ref_class_type.is_object()) { - /* Unreachable? Class file parser verifies Fieldref contents */ + if (!ref_class_type.is_object() && + (!allow_arrays || !ref_class_type.is_array())) { verify_error(ErrorContext::bad_type(bcs->bci(), TypeOrigin::cp(index, ref_class_type)), "Expecting reference to class in class %s at constant pool index %d", diff --git a/hotspot/src/share/vm/classfile/verifier.hpp b/hotspot/src/share/vm/classfile/verifier.hpp index ed9a173b187..515d36e5d27 100644 --- a/hotspot/src/share/vm/classfile/verifier.hpp +++ b/hotspot/src/share/vm/classfile/verifier.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, 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 @@ -297,7 +297,7 @@ class ClassVerifier : public StackObj { void verify_field_instructions( RawBytecodeStream* bcs, StackMapFrame* current_frame, - constantPoolHandle cp, TRAPS); + constantPoolHandle cp, bool allow_arrays, TRAPS); void verify_invoke_init( RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type, From 92b173203104e75085876756cd79a2b5bf2ef86f Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Wed, 14 Jan 2015 15:57:59 +0100 Subject: [PATCH 05/72] 8065576: Enable pipefail in the shell used by make to better detect build errors Reviewed-by: ihse, tbell, martin --- hotspot/make/aix/Makefile | 3 +-- hotspot/make/bsd/Makefile | 3 +-- hotspot/make/bsd/makefiles/dtrace.make | 18 +++++++++--------- hotspot/make/bsd/makefiles/universal.gmk | 4 ++-- hotspot/make/linux/Makefile | 3 +-- hotspot/make/linux/makefiles/vm.make | 6 ++---- hotspot/make/solaris/Makefile | 3 +-- hotspot/make/solaris/makefiles/dtrace.make | 10 +++++----- 8 files changed, 22 insertions(+), 28 deletions(-) diff --git a/hotspot/make/aix/Makefile b/hotspot/make/aix/Makefile index e0150749678..bbb92c9d75d 100644 --- a/hotspot/make/aix/Makefile +++ b/hotspot/make/aix/Makefile @@ -246,8 +246,7 @@ endif XSLT_CHECK = $(REMOTE) $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(REMOTE) $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \ diff --git a/hotspot/make/bsd/Makefile b/hotspot/make/bsd/Makefile index 3f0cfc36344..4d45841475e 100644 --- a/hotspot/make/bsd/Makefile +++ b/hotspot/make/bsd/Makefile @@ -240,8 +240,7 @@ endif XSLT_CHECK = $(REMOTE) $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(REMOTE) $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \ diff --git a/hotspot/make/bsd/makefiles/dtrace.make b/hotspot/make/bsd/makefiles/dtrace.make index dbb41163e39..80eb4d9a873 100644 --- a/hotspot/make/bsd/makefiles/dtrace.make +++ b/hotspot/make/bsd/makefiles/dtrace.make @@ -179,23 +179,23 @@ $(GENOFFS): $(DTRACE_SRCDIR)/$(GENOFFS)Main.c lib$(GENOFFS).dylib # $@.tmp is created first to avoid an empty $(JVMOFFS).h if an error occurs. $(JVMOFFS).h: $(GENOFFS) $(QUIETLY) DYLD_LIBRARY_PATH=.:$(DYLD_LIBRARY_PATH) ./$(GENOFFS) -header > $@.tmp; touch $@; \ - if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \ - then rm -f $@; mv $@.tmp $@; \ - else rm -f $@.tmp; \ + if diff $@.tmp $@ > /dev/null 2>&1 ; \ + then rm -f $@.tmp; \ + else rm -f $@; mv $@.tmp $@; \ fi $(JVMOFFS)Index.h: $(GENOFFS) $(QUIETLY) DYLD_LIBRARY_PATH=.:$(DYLD_LIBRARY_PATH) ./$(GENOFFS) -index > $@.tmp; touch $@; \ - if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \ - then rm -f $@; mv $@.tmp $@; \ - else rm -f $@.tmp; \ + if diff $@.tmp $@ > /dev/null 2>&1 ; \ + then rm -f $@.tmp; \ + else rm -f $@; mv $@.tmp $@; \ fi $(JVMOFFS).cpp: $(GENOFFS) $(JVMOFFS).h $(JVMOFFS)Index.h $(QUIETLY) DYLD_LIBRARY_PATH=.:$(DYLD_LIBRARY_PATH) ./$(GENOFFS) -table > $@.tmp; touch $@; \ - if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \ - then rm -f $@; mv $@.tmp $@; \ - else rm -f $@.tmp; \ + if diff $@.tmp $@ > /dev/null 2>&1; \ + then rm -f $@.tmp; \ + else rm -f $@; mv $@.tmp $@; \ fi $(JVMOFFS.o): $(JVMOFFS).h $(JVMOFFS).cpp diff --git a/hotspot/make/bsd/makefiles/universal.gmk b/hotspot/make/bsd/makefiles/universal.gmk index 12a34d70157..40868adf849 100644 --- a/hotspot/make/bsd/makefiles/universal.gmk +++ b/hotspot/make/bsd/makefiles/universal.gmk @@ -59,7 +59,7 @@ universalize: $(UNIVERSAL_LIPO_LIST) $(UNIVERSAL_COPY_LIST) # Package built libraries in a universal binary $(UNIVERSAL_LIPO_LIST): - BUILT_LIPO_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) 2>/dev/null`"; \ + BUILT_LIPO_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) 2>/dev/null`" || test $$? = "1"; \ if [ -n "$${BUILT_LIPO_FILES}" ]; then \ $(MKDIR) -p $(shell dirname $@); \ lipo -create -output $@ $${BUILT_LIPO_FILES}; \ @@ -70,7 +70,7 @@ $(UNIVERSAL_LIPO_LIST): # - copies directories; including empty dirs # - copies files, symlinks, other non-directory files $(UNIVERSAL_COPY_LIST): - BUILT_COPY_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) -prune 2>/dev/null`"; \ + BUILT_COPY_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) -prune 2>/dev/null`" || test $$? = "1"; \ if [ -n "$${BUILT_COPY_FILES}" ]; then \ for i in $${BUILT_COPY_FILES}; do \ $(MKDIR) -p $(shell dirname $@); \ diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile index c3ed19f09f1..33ed65db9b8 100644 --- a/hotspot/make/linux/Makefile +++ b/hotspot/make/linux/Makefile @@ -246,8 +246,7 @@ endif XSLT_CHECK = $(REMOTE) $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(REMOTE) $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \ diff --git a/hotspot/make/linux/makefiles/vm.make b/hotspot/make/linux/makefiles/vm.make index a138a163f20..65b11f544d0 100644 --- a/hotspot/make/linux/makefiles/vm.make +++ b/hotspot/make/linux/makefiles/vm.make @@ -334,10 +334,8 @@ $(LIBJVM): $(LIBJVM.o) $(LIBJVM_MAPFILE) $(LD_SCRIPT) rm -f $@.1; ln -s $@ $@.1; \ if [ \"$(CROSS_COMPILE_ARCH)\" = \"\" ] ; then \ if [ -x /usr/sbin/selinuxenabled ] ; then \ - /usr/sbin/selinuxenabled; \ - if [ $$? = 0 ] ; then \ - /usr/bin/chcon -t textrel_shlib_t $@; \ - if [ $$? != 0 ]; then \ + if /usr/sbin/selinuxenabled; then \ + if ! /usr/bin/chcon -t textrel_shlib_t $@; then \ echo "ERROR: Cannot chcon $@"; \ fi \ fi \ diff --git a/hotspot/make/solaris/Makefile b/hotspot/make/solaris/Makefile index 869db69646d..f8fb06c8725 100644 --- a/hotspot/make/solaris/Makefile +++ b/hotspot/make/solaris/Makefile @@ -190,8 +190,7 @@ endif XSLT_CHECK = $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \ diff --git a/hotspot/make/solaris/makefiles/dtrace.make b/hotspot/make/solaris/makefiles/dtrace.make index be6e71dba9e..1b76dc74d6a 100644 --- a/hotspot/make/solaris/makefiles/dtrace.make +++ b/hotspot/make/solaris/makefiles/dtrace.make @@ -171,11 +171,11 @@ $(GENOFFS): $(DTRACE_SRCDIR)/$(GENOFFS)Main.c lib$(GENOFFS).so ./lib$(GENOFFS).so CONDITIONALLY_UPDATE_JVMOFFS_TARGET = \ - cmp -s $@ $@.tmp; \ - case $$? in \ - 0) rm -f $@.tmp;; \ - *) rm -f $@ && mv $@.tmp $@ && echo Updated $@;; \ - esac + if cmp -s $@ $@.tmp; then \ + rm -f $@.tmp; \ + else \ + rm -f $@ && mv $@.tmp $@ && echo Updated $@; \ + fi # $@.tmp is created first to avoid an empty $(JVMOFFS).h if an error occurs. $(JVMOFFS).h: $(GENOFFS) From 530e7bd26fadcfa4ae33c4a6fdafacc4edf5646d Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Wed, 14 Jan 2015 16:03:59 +0100 Subject: [PATCH 06/72] 8065576: Enable pipefail in the shell used by make to better detect build errors Reviewed-by: ihse, tbell, martin --- common/autoconf/basics.m4 | 23 ++++++++++++++++++ common/autoconf/configure.ac | 1 + common/autoconf/generated-configure.sh | 32 +++++++++++++++++++++++++- common/autoconf/spec.gmk.in | 6 ++++- make/common/JavaCompilation.gmk | 21 ++++++++++++----- make/common/MakeBase.gmk | 2 +- make/common/NativeCompilation.gmk | 3 ++- 7 files changed, 78 insertions(+), 10 deletions(-) diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4 index 62d83574289..800c52b844b 100644 --- a/common/autoconf/basics.m4 +++ b/common/autoconf/basics.m4 @@ -987,3 +987,26 @@ AC_DEFUN_ONCE([BASIC_TEST_USABILITY_ISSUES], IS_RECONFIGURE=no fi ]) + +# Check for support for specific options in bash +AC_DEFUN_ONCE([BASIC_CHECK_BASH_OPTIONS], +[ + # Test if bash supports pipefail. + AC_MSG_CHECKING([if bash supports pipefail]) + if ${BASH} -c 'set -o pipefail'; then + BASH_ARGS="$BASH_ARGS -o pipefail" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + AC_MSG_CHECKING([if bash supports errexit (-e)]) + if ${BASH} -e -c 'true'; then + BASH_ARGS="$BASH_ARGS -e" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + AC_SUBST(BASH_ARGS) +]) diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac index 146556f479e..902ba475684 100644 --- a/common/autoconf/configure.ac +++ b/common/autoconf/configure.ac @@ -113,6 +113,7 @@ HELP_SETUP_DEPENDENCY_HELP # Setup tools that requires more complex handling, or that is not needed by the configure script. BASIC_SETUP_COMPLEX_TOOLS +BASIC_CHECK_BASH_OPTIONS # Check if pkg-config is available. PKG_PROG_PKG_CONFIG diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 59c1a8ae9e8..11b5d337733 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -853,6 +853,7 @@ OS_VERSION_MICRO OS_VERSION_MINOR OS_VERSION_MAJOR PKG_CONFIG +BASH_ARGS CODESIGN XATTR DSYMUTIL @@ -3522,6 +3523,9 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. +# Check for support for specific options in bash + + # # Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -4329,7 +4333,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++" #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1418395009 +DATE_WHEN_GENERATED=1421247827 ############################################################################### # @@ -19609,6 +19613,32 @@ $as_echo "yes" >&6; } fi + # Test if bash supports pipefail. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if bash supports pipefail" >&5 +$as_echo_n "checking if bash supports pipefail... " >&6; } + if ${BASH} -c 'set -o pipefail'; then + BASH_ARGS="$BASH_ARGS -o pipefail" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if bash supports errexit (-e)" >&5 +$as_echo_n "checking if bash supports errexit (-e)... " >&6; } + if ${BASH} -e -c 'true'; then + BASH_ARGS="$BASH_ARGS -e" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + + + # Check if pkg-config is available. diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 60d70886925..5cb01dd4adc 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -78,6 +78,11 @@ endif OUTPUT_SYNC_SUPPORTED:=@OUTPUT_SYNC_SUPPORTED@ OUTPUT_SYNC:=@OUTPUT_SYNC@ +# Override the shell with bash +BASH:=@BASH@ +BASH_ARGS:=@BASH_ARGS@ +SHELL:=$(BASH) $(BASH_ARGS) + # The "human readable" name of this configuration CONF_NAME:=@CONF_NAME@ @@ -495,7 +500,6 @@ endif # Tools adhering to a minimal and common standard of posix compliance. AWK:=@AWK@ BASENAME:=@BASENAME@ -BASH:=@BASH@ CAT:=@CAT@ CCACHE:=@CCACHE@ # CD is going away, but remains to cater for legacy makefiles. diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index 6c6e515c816..9734ba9978a 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -126,17 +126,20 @@ define SetupArchiveInner $1_FIND_PATTERNS:=$(FALSE_FIND_PATTERN) $$(patsubst %,$(SPACE)-o$(SPACE)-name$(SPACE)$(DQUOTE)*%$(DQUOTE),$$($1_SUFFIXES)) # On windows, a lot of includes/excludes risk making the command line too long, so # writing the grep patterns to files. + # Grep returns 1 if nothing is matched. Do not fail the build for this. ifneq (,$$($1_INCLUDES)) $1_GREP_INCLUDE_PATTERNS:=$$(call EscapeDollar, \ $$(foreach src,$$($1_SRCS), $$(addprefix $$(src)/,$$($1_INCLUDES)))) # If there are a lot of include patterns, output to file to shorten command lines ifeq ($$(word 20,$$($1_GREP_INCLUDE_PATTERNS)),) - $1_GREP_INCLUDES:=| $(GREP) $$(patsubst %,$(SPACE)-e$(SPACE)$(DQUOTE)%$(DQUOTE),$$($1_GREP_INCLUDE_PATTERNS)) + $1_GREP_INCLUDES:=| ( $(GREP) $$(patsubst %,$(SPACE)-e$(SPACE)$(DQUOTE)%$(DQUOTE),$$($1_GREP_INCLUDE_PATTERNS)) \ + || test "$$$$?" = "1" ) else $1_GREP_INCLUDE_OUTPUT:=$(RM) $$($1_BIN)/_the.$$($1_JARNAME)_include $$(NEWLINE) \ $$(call ListPathsSafely,$1_GREP_INCLUDE_PATTERNS,\n, \ >> $$($1_BIN)/_the.$$($1_JARNAME)_include) - $1_GREP_INCLUDES:=| $(GREP) -f $$($1_BIN)/_the.$$($1_JARNAME)_include + $1_GREP_INCLUDES:=| ( $(GREP) -f $$($1_BIN)/_the.$$($1_JARNAME)_include \ + || test "$$$$?" = "1" ) endif endif ifneq (,$$($1_EXCLUDES)$$($1_EXCLUDE_FILES)) @@ -145,12 +148,14 @@ define SetupArchiveInner $$($1_EXCLUDES) $$($1_EXCLUDE_FILES)))) # If there are a lot of include patterns, output to file to shorten command lines ifeq ($$(word 20,$$($1_GREP_EXCLUDE_PATTERNS)),) - $1_GREP_EXCLUDES:=| $(GREP) -v $$(patsubst %,$(SPACE)-e$(SPACE)$(DQUOTE)%$(DQUOTE),$$($1_GREP_EXCLUDE_PATTERNS)) + $1_GREP_EXCLUDES:=| ( $(GREP) -v $$(patsubst %,$(SPACE)-e$(SPACE)$(DQUOTE)%$(DQUOTE),$$($1_GREP_EXCLUDE_PATTERNS)) \ + || test "$$$$?" = "1" ) else $1_GREP_EXCLUDE_OUTPUT=$(RM) $$($1_BIN)/_the.$$($1_JARNAME)_exclude $$(NEWLINE) \ $$(call ListPathsSafely,$1_GREP_EXCLUDE_PATTERNS,\n, \ >> $$($1_BIN)/_the.$$($1_JARNAME)_exclude) - $1_GREP_EXCLUDES:=| $(GREP) -v -f $$($1_BIN)/_the.$$($1_JARNAME)_exclude + $1_GREP_EXCLUDES:=| ( $(GREP) -v -f $$($1_BIN)/_the.$$($1_JARNAME)_exclude \ + || test "$$$$?" = "1" ) endif endif @@ -222,9 +227,11 @@ define SetupArchiveInner $$($1_CAPTURE_EXTRA_FILES) # The capture metainf macro finds all files below the META-INF directory that are newer than the jar-file. + # Find returns non zero if the META-INF dir does not exist, ignore this. ifeq (,$$($1_SKIP_METAINF)) $1_CAPTURE_METAINF =$$(foreach src,$$($1_SRCS), \ - ( $(FIND) $$(src)/META-INF -type f -a -newer $$@ 2> /dev/null | $(SED) 's|$$(src)/|-C $$(src) |g' >> \ + ( ( $(FIND) $$(src)/META-INF -type f -a -newer $$@ 2> /dev/null || true ) \ + | $(SED) 's|$$(src)/|-C $$(src) |g' >> \ $$($1_BIN)/_the.$$($1_JARNAME)_contents ) $$(NEWLINE) ) endif # The capture deletes macro finds all deleted files and concatenates them. The resulting file @@ -248,9 +255,11 @@ define SetupArchiveInner >> $$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE)) \ $$($1_CAPTURE_EXTRA_FILES) + # Find returns non zero if the META-INF dir does not exist, ignore this. ifeq (,$$($1_SKIP_METAINF)) $1_SCAPTURE_METAINF=$$(foreach src,$$($1_SRCS), \ - ( $(FIND) $$(src)/META-INF -type f 2> /dev/null | $(SED) 's|$$(src)/|-C $$(src) |g' >> \ + ( ( $(FIND) $$(src)/META-INF -type f 2> /dev/null || true ) \ + | $(SED) 's|$$(src)/|-C $$(src) |g' >> \ $$($1_BIN)/_the.$$($1_JARNAME)_contents) $$(NEWLINE) ) endif $1_SUPDATE_CONTENTS=$(JAR) $$($1_JAR_UPDATE_OPTIONS) $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE) diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index b45fd52d5cd..e1047aff868 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -349,7 +349,7 @@ define SetupLogging # (and causing a crash on Cygwin). # Default shell seems to always be /bin/sh. Must override with bash to get this to work on Solaris. # Only use time if it's GNU time which supports format and output file. - WRAPPER_SHELL:=$$(BASH) $$(SRC_ROOT)/common/bin/shell-tracer.sh $$(if $$(findstring yes,$$(IS_GNU_TIME)),$$(TIME),-) $$(OUTPUT_ROOT)/build-trace-time.log $$(BASH) + WRAPPER_SHELL:=$$(BASH) $$(SRC_ROOT)/common/bin/shell-tracer.sh $$(if $$(findstring yes,$$(IS_GNU_TIME)),$$(TIME),-) $$(OUTPUT_ROOT)/build-trace-time.log $$(SHELL) SHELL=$$(warning $$(if $$@,Building $$@,Running shell command) $$(if $$<, (from $$<))$$(if $$?, ($$(wordlist 1, 20, $$?) $$(if $$(wordlist 21, 22, $$?), ... [in total $$(words $$?) files]) newer)))$$(WRAPPER_SHELL) endif # Never remove warning messages; this is just for completeness diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index ad2af57c0fd..a4fb3bf6fc7 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -133,7 +133,8 @@ define add_native_source ($$($1_$2_COMP) $$($1_$2_FLAGS) -showIncludes $$($1_$2_DEBUG_OUT_FLAGS) \ $(CC_OUT_OPTION)$$($1_$2_OBJ) $2 ; echo $$$$? > $$($1_$2_DEP).exitvalue) \ | $(TEE) $$($1_$2_DEP).raw | $(GREP) -v -e "^Note: including file:" \ - -e "^$(notdir $2)$$$$" ; exit `cat $$($1_$2_DEP).exitvalue` + -e "^$(notdir $2)$$$$" || test "$$$$?" = "1" ; \ + exit `cat $$($1_$2_DEP).exitvalue` $(RM) $$($1_$2_DEP).exitvalue ($(ECHO) $$@: \\ \ && $(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_$2_DEP).raw) > $$($1_$2_DEP) From 885e6ddf67a068c53c769d3212d329dda13521c6 Mon Sep 17 00:00:00 2001 From: Dmitry Samersoff Date: Wed, 14 Jan 2015 07:10:53 -0800 Subject: [PATCH 07/72] 7076820: assert(addr != 0) failed: address sanity check in PerfMemory::detach with -XX:-UsePerfData Explicitly checks for UsePerfData and if it's false make Perf:detach a NOP. Reviewed-by: dholmes, jbachorik --- hotspot/src/share/vm/prims/perf.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hotspot/src/share/vm/prims/perf.cpp b/hotspot/src/share/vm/prims/perf.cpp index 9ad0f4c56fe..bddb1f7b4b3 100644 --- a/hotspot/src/share/vm/prims/perf.cpp +++ b/hotspot/src/share/vm/prims/perf.cpp @@ -100,6 +100,11 @@ PERF_ENTRY(void, Perf_Detach(JNIEnv *env, jobject unused, jobject buffer)) PerfWrapper("Perf_Detach"); + if (!UsePerfData) { + // With -XX:-UsePerfData, detach is just a NOP + return; + } + void* address = 0; jlong capacity = 0; From 834ff91cc512c02525d832ae5ae713cadaaf766e Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Wed, 14 Jan 2015 17:27:00 -0800 Subject: [PATCH 08/72] 8068864: C2 failed: modified node is not on IGVN._worklist Use igvn.replace_input_of() instead of set_req(). Reviewed-by: iveresov, vlivanov --- hotspot/src/share/vm/opto/loopTransform.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index b917ee113c0..f61e335a5c4 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -2057,10 +2057,9 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { } Node *main_cmp = main_bol->in(1); if( main_cmp->outcnt() > 1 ) { // CmpNode shared? - _igvn.hash_delete(main_bol); main_cmp = main_cmp->clone();// Clone a private CmpNode register_new_node( main_cmp, main_cle->in(0) ); - main_bol->set_req(1,main_cmp); + _igvn.replace_input_of(main_bol, 1, main_cmp); } // Hack the now-private loop bounds _igvn.replace_input_of(main_cmp, 2, main_limit); From bfe8fc743315da408d8308085a3cf10d05fd87c0 Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Thu, 15 Jan 2015 11:18:20 +0100 Subject: [PATCH 09/72] 8054494: Remove sun.misc.Unsafe.monitorEnter, monitorExit and tryMonitorEnter Co-authored-by: Filipp Zhinkin Reviewed-by: dholmes, coleenp --- hotspot/src/share/vm/prims/unsafe.cpp | 51 +------------------ hotspot/src/share/vm/runtime/synchronizer.cpp | 14 +---- hotspot/src/share/vm/runtime/synchronizer.hpp | 3 +- .../compiler/testlibrary/rtm/BusyLock.java | 22 ++------ 4 files changed, 7 insertions(+), 83 deletions(-) diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp index 68a729ae03c..f681ccebd9d 100644 --- a/hotspot/src/share/vm/prims/unsafe.cpp +++ b/hotspot/src/share/vm/prims/unsafe.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, 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 @@ -1104,43 +1104,6 @@ UNSAFE_END -UNSAFE_ENTRY(void, Unsafe_MonitorEnter(JNIEnv *env, jobject unsafe, jobject jobj)) - UnsafeWrapper("Unsafe_MonitorEnter"); - { - if (jobj == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - Handle obj(thread, JNIHandles::resolve_non_null(jobj)); - ObjectSynchronizer::jni_enter(obj, CHECK); - } -UNSAFE_END - - -UNSAFE_ENTRY(jboolean, Unsafe_TryMonitorEnter(JNIEnv *env, jobject unsafe, jobject jobj)) - UnsafeWrapper("Unsafe_TryMonitorEnter"); - { - if (jobj == NULL) { - THROW_(vmSymbols::java_lang_NullPointerException(), JNI_FALSE); - } - Handle obj(thread, JNIHandles::resolve_non_null(jobj)); - bool res = ObjectSynchronizer::jni_try_enter(obj, CHECK_0); - return (res ? JNI_TRUE : JNI_FALSE); - } -UNSAFE_END - - -UNSAFE_ENTRY(void, Unsafe_MonitorExit(JNIEnv *env, jobject unsafe, jobject jobj)) - UnsafeWrapper("Unsafe_MonitorExit"); - { - if (jobj == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - Handle obj(THREAD, JNIHandles::resolve_non_null(jobj)); - ObjectSynchronizer::jni_exit(obj(), CHECK); - } -UNSAFE_END - - UNSAFE_ENTRY(void, Unsafe_ThrowException(JNIEnv *env, jobject unsafe, jthrowable thr)) UnsafeWrapper("Unsafe_ThrowException"); { @@ -1365,8 +1328,6 @@ static JNINativeMethod methods_140[] = { {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)} }; @@ -1411,8 +1372,6 @@ static JNINativeMethod methods_141[] = { {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)} }; @@ -1461,8 +1420,6 @@ static JNINativeMethod methods_15[] = { {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)}, {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC"compareAndSwapInt", CC"("OBJ"J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, @@ -1515,9 +1472,6 @@ static JNINativeMethod methods_16[] = { {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, - {CC"tryMonitorEnter", CC"("OBJ")Z", FN_PTR(Unsafe_TryMonitorEnter)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)}, {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC"compareAndSwapInt", CC"("OBJ"J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, @@ -1571,9 +1525,6 @@ static JNINativeMethod methods_18[] = { {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, - {CC"tryMonitorEnter", CC"("OBJ")Z", FN_PTR(Unsafe_TryMonitorEnter)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)}, {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC"compareAndSwapInt", CC"("OBJ"J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, diff --git a/hotspot/src/share/vm/runtime/synchronizer.cpp b/hotspot/src/share/vm/runtime/synchronizer.cpp index a64d5b920d4..7f829ba6991 100644 --- a/hotspot/src/share/vm/runtime/synchronizer.cpp +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, 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 @@ -276,18 +276,6 @@ void ObjectSynchronizer::jni_enter(Handle obj, TRAPS) { THREAD->set_current_pending_monitor_is_from_java(true); } -// NOTE: must use heavy weight monitor to handle jni monitor enter -bool ObjectSynchronizer::jni_try_enter(Handle obj, Thread* THREAD) { - if (UseBiasedLocking) { - BiasedLocking::revoke_and_rebias(obj, false, THREAD); - assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now"); - } - - ObjectMonitor* monitor = ObjectSynchronizer::inflate_helper(obj()); - return monitor->try_enter(THREAD); -} - - // NOTE: must use heavy weight monitor to handle jni monitor exit void ObjectSynchronizer::jni_exit(oop obj, Thread* THREAD) { TEVENT(jni_exit); diff --git a/hotspot/src/share/vm/runtime/synchronizer.hpp b/hotspot/src/share/vm/runtime/synchronizer.hpp index a823b540ec4..f2ff4c6f100 100644 --- a/hotspot/src/share/vm/runtime/synchronizer.hpp +++ b/hotspot/src/share/vm/runtime/synchronizer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, 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 @@ -65,7 +65,6 @@ class ObjectSynchronizer : AllStatic { // Used only to handle jni locks or other unmatched monitor enter/exit // Internally they will use heavy weight monitor. static void jni_enter(Handle obj, TRAPS); - static bool jni_try_enter(Handle obj, Thread* THREAD); // Implements Unsafe.tryMonitorEnter static void jni_exit(oop obj, Thread* THREAD); // Handle all interpreter, compiler and jni cases diff --git a/hotspot/test/compiler/testlibrary/rtm/BusyLock.java b/hotspot/test/compiler/testlibrary/rtm/BusyLock.java index 55985b61b73..879edb830d6 100644 --- a/hotspot/test/compiler/testlibrary/rtm/BusyLock.java +++ b/hotspot/test/compiler/testlibrary/rtm/BusyLock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -24,9 +24,6 @@ package rtm; -import com.oracle.java.testlibrary.Utils; -import sun.misc.Unsafe; - import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; @@ -42,7 +39,6 @@ public class BusyLock implements CompilableTest, Runnable { // Following field have to be static in order to avoid escape analysis. @SuppressWarnings("UnsuedDeclaration") private static int field = 0; - private static final Unsafe UNSAFE = Utils.getUnsafe(); protected final Object monitor; protected final int timeout; @@ -59,18 +55,9 @@ public class BusyLock implements CompilableTest, Runnable { @Override public void run() { try { - // wait until forceAbort leave monitor - barrier.await(); - if (UNSAFE.tryMonitorEnter(monitor)) { - try { - barrier.await(); - Thread.sleep(timeout); - } finally { - UNSAFE.monitorExit(monitor); - } - } else { - throw new RuntimeException("Monitor should be entered by " + - "::run() first."); + synchronized (monitor) { + barrier.await(); + Thread.sleep(timeout); } } catch (InterruptedException | BrokenBarrierException e) { throw new RuntimeException("Synchronization error happened.", e); @@ -79,7 +66,6 @@ public class BusyLock implements CompilableTest, Runnable { public void syncAndTest() { try { - barrier.await(); // wait until monitor is locked by a ::run method barrier.await(); } catch (InterruptedException | BrokenBarrierException e) { From 9d6b3c1d71fbd0d1065472d0ca83ad6f6ca2987a Mon Sep 17 00:00:00 2001 From: Zoltan Majo Date: Thu, 15 Jan 2015 11:30:13 +0100 Subject: [PATCH 10/72] 8067374: Use %f instead of %g for LogCompilation output Changed format string from %g to %f. Reviewed-by: kvn --- hotspot/src/share/vm/opto/doCall.cpp | 2 +- hotspot/src/share/vm/opto/parse1.cpp | 2 +- hotspot/src/share/vm/opto/parse2.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/opto/doCall.cpp b/hotspot/src/share/vm/opto/doCall.cpp index 7397f9e27cb..1697d7ee29e 100644 --- a/hotspot/src/share/vm/opto/doCall.cpp +++ b/hotspot/src/share/vm/opto/doCall.cpp @@ -94,7 +94,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool if (log != NULL) { int rid = (receiver_count >= 0)? log->identify(profile.receiver(0)): -1; int r2id = (rid != -1 && profile.has_receiver(1))? log->identify(profile.receiver(1)):-1; - log->begin_elem("call method='%d' count='%d' prof_factor='%g'", + log->begin_elem("call method='%d' count='%d' prof_factor='%f'", log->identify(callee), site_count, prof_factor); if (call_does_dispatch) log->print(" virtual='1'"); if (allow_inline) log->print(" inline='1'"); diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index 402ccfe5dc6..35728e6dd17 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -441,7 +441,7 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) CompileLog* log = C->log(); if (log != NULL) { - log->begin_head("parse method='%d' uses='%g'", + log->begin_head("parse method='%d' uses='%f'", log->identify(parse_method), expected_uses); if (depth() == 1 && C->is_osr_compilation()) { log->print(" osr_bci='%d'", C->entry_bci()); diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index 8a319f848c1..c99ac9659d1 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -832,7 +832,7 @@ float Parse::dynamic_branch_prediction(float &cnt) { sprintf(prob_str_buf, "%g", prob); prob_str = prob_str_buf; } - C->log()->elem("branch target_bci='%d' taken='%d' not_taken='%d' cnt='%g' prob='%s'", + C->log()->elem("branch target_bci='%d' taken='%d' not_taken='%d' cnt='%f' prob='%s'", iter().get_dest(), taken, not_taken, cnt, prob_str); } return prob; From 71d4cfb1ada85784c22cbb4c1ed47c22ed7d285a Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 15 Jan 2015 16:05:20 +0100 Subject: [PATCH 11/72] 8068026: [TESTBUG] Check for -client in gc/g1/TestHumongousCodeCacheRoots.java Skip test if -client is not supported. Reviewed-by: jwilhelm, simonis --- hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java b/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java index c4a81e2d5f0..c24b3ecf867 100644 --- a/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java +++ b/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java @@ -116,7 +116,14 @@ public class TestHumongousCodeCacheRoots { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(finalargs.toArray(new String[0])); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); + try { + output.shouldHaveExitValue(0); + } catch (RuntimeException e) { + // It's ok if there is no client vm in the jdk. + if (output.firstMatch("Unrecognized option: -client") == null) { + throw e; + } + } return output; } From 4f3c9fccb791287a8733d5f561624f60c36d7325 Mon Sep 17 00:00:00 2001 From: Christian Tornqvist Date: Thu, 15 Jan 2015 14:10:49 -0800 Subject: [PATCH 12/72] 8062961: [TESTBUG] Spurious timeout for runtime/ErrorHandling/ProblematicFrameTest Reviewed-by: coleenp, gtriantafill --- hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java b/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java index 9ce9f763889..2ad3fc12686 100644 --- a/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java +++ b/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -44,7 +44,7 @@ public class ProblematicFrameTest { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-Xmx64m", "-XX:-TransmitErrorReport", Crasher.class.getName()); + "-Xmx64m", "-XX:-TransmitErrorReport", "-XX:-CreateMinidumpOnCrash", Crasher.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotMatch("error occurred during error reporting \\(printing problematic frame\\)"); } From 781a793ed9c740f77ce931d9df09b030de3d216a Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Fri, 16 Jan 2015 09:15:22 +0100 Subject: [PATCH 13/72] 6584008: jvmtiStringPrimitiveCallback should not be invoked when string value is null Reviewed-by: sla, sspitsyn --- hotspot/src/share/vm/prims/jvmtiTagMap.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp index 89680d13ea6..31ab6f59bc2 100644 --- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp @@ -1046,10 +1046,16 @@ static jint invoke_string_value_callback(jvmtiStringPrimitiveValueCallback cb, { assert(str->klass() == SystemDictionary::String_klass(), "not a string"); + typeArrayOop s_value = java_lang_String::value(str); + + // JDK-6584008: the value field may be null if a String instance is + // partially constructed. + if (s_value == NULL) { + return 0; + } // get the string value and length // (string value may be offset from the base) int s_len = java_lang_String::length(str); - typeArrayOop s_value = java_lang_String::value(str); int s_offset = java_lang_String::offset(str); jchar* value; if (s_len > 0) { From 788b0d89f877a30a3ac539ce2a5eecdfddda8699 Mon Sep 17 00:00:00 2001 From: Jungwoo Ha Date: Fri, 16 Jan 2015 09:40:13 +0100 Subject: [PATCH 14/72] 8061259: ParNew promotion failed is serialized on a lock Reviewed-by: kbarrett, brutisso --- .../share/vm/gc_implementation/parNew/parNewGeneration.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp index a56c94823db..30ef7ceb2c1 100644 --- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp @@ -1194,8 +1194,10 @@ oop ParNewGeneration::copy_to_survivor_space( return real_forwardee(old); } - new_obj = _next_gen->par_promote(par_scan_state->thread_num(), - old, m, sz); + if (!_promotion_failed) { + new_obj = _next_gen->par_promote(par_scan_state->thread_num(), + old, m, sz); + } if (new_obj == NULL) { // promotion failed, forward to self From 86f95c464ff2c06fef9bed4c9fb80854691a095b Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Fri, 16 Jan 2015 10:29:12 +0100 Subject: [PATCH 15/72] 8066875: VirtualSpace does not use large pages Reviewed-by: stefank, tschatzl, anoll, thartmann --- hotspot/src/share/vm/code/codeCache.cpp | 4 +- .../parallelScavenge/generationSizer.cpp | 4 +- .../parallelScavenge/parMarkBitMap.cpp | 2 +- .../parallelScavenge/psParallelCompact.cpp | 2 +- hotspot/src/share/vm/memory/heap.cpp | 4 +- hotspot/src/share/vm/runtime/os.cpp | 60 ++++++++++++++++--- hotspot/src/share/vm/runtime/os.hpp | 10 +++- hotspot/src/share/vm/runtime/virtualspace.cpp | 7 ++- 8 files changed, 71 insertions(+), 22 deletions(-) diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index af50207fbbf..5a546f50b4f 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -233,8 +233,8 @@ void CodeCache::initialize_heaps() { ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size) { // Determine alignment const size_t page_size = os::can_execute_large_page_memory() ? - MIN2(os::page_size_for_region(InitialCodeCacheSize, 8), - os::page_size_for_region(size, 8)) : + MIN2(os::page_size_for_region_aligned(InitialCodeCacheSize, 8), + os::page_size_for_region_aligned(size, 8)) : os::vm_page_size(); const size_t granularity = os::vm_allocation_granularity(); const size_t r_align = MAX2(page_size, granularity); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp index 29fb547437f..a6cef462ad9 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp @@ -61,9 +61,9 @@ void GenerationSizer::initialize_flags() { void GenerationSizer::initialize_size_info() { trace_gen_sizes("ps heap raw"); - const size_t max_page_sz = os::page_size_for_region(_max_heap_byte_size, 8); + const size_t max_page_sz = os::page_size_for_region_aligned(_max_heap_byte_size, 8); const size_t min_pages = 4; // 1 for eden + 1 for each survivor + 1 for old - const size_t min_page_sz = os::page_size_for_region(_min_heap_byte_size, min_pages); + const size_t min_page_sz = os::page_size_for_region_aligned(_min_heap_byte_size, min_pages); const size_t page_sz = MIN2(max_page_sz, min_page_sz); // Can a page size be something else than a power of two? diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp index a8ab19357ce..33e8f3f9b9c 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp @@ -41,7 +41,7 @@ ParMarkBitMap::initialize(MemRegion covered_region) const size_t words = bits / BitsPerWord; const size_t raw_bytes = words * sizeof(idx_t); - const size_t page_sz = os::page_size_for_region(raw_bytes, 10); + const size_t page_sz = os::page_size_for_region_aligned(raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); _reserved_byte_size = align_size_up(raw_bytes, MAX2(page_sz, granularity)); diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp index a546e548370..28cff7813d7 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp @@ -403,7 +403,7 @@ PSVirtualSpace* ParallelCompactData::create_vspace(size_t count, size_t element_size) { const size_t raw_bytes = count * element_size; - const size_t page_sz = os::page_size_for_region(raw_bytes, 10); + const size_t page_sz = os::page_size_for_region_aligned(raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); _reserved_byte_size = align_size_up(raw_bytes, MAX2(page_sz, granularity)); diff --git a/hotspot/src/share/vm/memory/heap.cpp b/hotspot/src/share/vm/memory/heap.cpp index 5ba099e78e8..4612f6a80f7 100644 --- a/hotspot/src/share/vm/memory/heap.cpp +++ b/hotspot/src/share/vm/memory/heap.cpp @@ -104,8 +104,8 @@ bool CodeHeap::reserve(ReservedSpace rs, size_t committed_size, size_t segment_s size_t page_size = os::vm_page_size(); if (os::can_execute_large_page_memory()) { const size_t min_pages = 8; - page_size = MIN2(os::page_size_for_region(committed_size, min_pages), - os::page_size_for_region(rs.size(), min_pages)); + page_size = MIN2(os::page_size_for_region_aligned(committed_size, min_pages), + os::page_size_for_region_aligned(rs.size(), min_pages)); } const size_t granularity = os::vm_allocation_granularity(); diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index 665688b6808..adf08340257 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -1399,15 +1399,17 @@ bool os::stack_shadow_pages_available(Thread *thread, methodHandle method) { return (sp > (stack_limit + reserved_area)); } -size_t os::page_size_for_region(size_t region_size, size_t min_pages) { +size_t os::page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned) { assert(min_pages > 0, "sanity"); if (UseLargePages) { const size_t max_page_size = region_size / min_pages; for (size_t i = 0; _page_sizes[i] != 0; ++i) { const size_t page_size = _page_sizes[i]; - if (page_size <= max_page_size && is_size_aligned(region_size, page_size)) { - return page_size; + if (page_size <= max_page_size) { + if (!must_be_aligned || is_size_aligned(region_size, page_size)) { + return page_size; + } } } } @@ -1415,6 +1417,14 @@ size_t os::page_size_for_region(size_t region_size, size_t min_pages) { return vm_page_size(); } +size_t os::page_size_for_region_aligned(size_t region_size, size_t min_pages) { + return page_size_for_region(region_size, min_pages, true); +} + +size_t os::page_size_for_region_unaligned(size_t region_size, size_t min_pages) { + return page_size_for_region(region_size, min_pages, false); +} + #ifndef PRODUCT void os::trace_page_sizes(const char* str, const size_t* page_sizes, int count) { @@ -1663,17 +1673,17 @@ class TestOS : AllStatic { static size_t large_page_size() { const size_t large_page_size_example = 4 * M; - return os::page_size_for_region(large_page_size_example, 1); + return os::page_size_for_region_aligned(large_page_size_example, 1); } - static void test_page_size_for_region() { + static void test_page_size_for_region_aligned() { if (UseLargePages) { const size_t small_page = small_page_size(); const size_t large_page = large_page_size(); if (large_page > small_page) { size_t num_small_pages_in_large = large_page / small_page; - size_t page = os::page_size_for_region(large_page, num_small_pages_in_large); + size_t page = os::page_size_for_region_aligned(large_page, num_small_pages_in_large); assert_eq(page, small_page); } @@ -1686,21 +1696,53 @@ class TestOS : AllStatic { const size_t large_page = large_page_size(); if (large_page > small_page) { const size_t unaligned_region = large_page + 17; - size_t page = os::page_size_for_region(unaligned_region, 1); + size_t page = os::page_size_for_region_aligned(unaligned_region, 1); assert_eq(page, small_page); const size_t num_pages = 5; const size_t aligned_region = large_page * num_pages; - page = os::page_size_for_region(aligned_region, num_pages); + page = os::page_size_for_region_aligned(aligned_region, num_pages); assert_eq(page, large_page); } } } + static void test_page_size_for_region_unaligned() { + if (UseLargePages) { + // Given exact page size, should return that page size. + for (size_t i = 0; os::_page_sizes[i] != 0; i++) { + size_t expected = os::_page_sizes[i]; + size_t actual = os::page_size_for_region_unaligned(expected, 1); + assert_eq(expected, actual); + } + + // Given slightly larger size than a page size, return the page size. + for (size_t i = 0; os::_page_sizes[i] != 0; i++) { + size_t expected = os::_page_sizes[i]; + size_t actual = os::page_size_for_region_unaligned(expected + 17, 1); + assert_eq(expected, actual); + } + + // Given a slightly smaller size than a page size, + // return the next smaller page size. + if (os::_page_sizes[1] > os::_page_sizes[0]) { + size_t expected = os::_page_sizes[0]; + size_t actual = os::page_size_for_region_unaligned(os::_page_sizes[1] - 17, 1); + assert_eq(actual, expected); + } + + // Return small page size for values less than a small page. + size_t small_page = small_page_size(); + size_t actual = os::page_size_for_region_unaligned(small_page - 17, 1); + assert_eq(small_page, actual); + } + } + public: static void run_tests() { - test_page_size_for_region(); + test_page_size_for_region_aligned(); test_page_size_for_region_alignment(); + test_page_size_for_region_unaligned(); } }; diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index ecd2e24a0fa..67f22264d96 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -148,6 +148,7 @@ class os: AllStatic { static void pd_free_memory(char *addr, size_t bytes, size_t alignment_hint); static void pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint); + static size_t page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned); public: static void init(void); // Called before command line parsing @@ -267,8 +268,13 @@ class os: AllStatic { // Returns the page size to use for a region of memory. // region_size / min_pages will always be greater than or equal to the - // returned value. - static size_t page_size_for_region(size_t region_size, size_t min_pages); + // returned value. The returned value will divide region_size. + static size_t page_size_for_region_aligned(size_t region_size, size_t min_pages); + + // Returns the page size to use for a region of memory. + // region_size / min_pages will always be greater than or equal to the + // returned value. The returned value might not divide region_size. + static size_t page_size_for_region_unaligned(size_t region_size, size_t min_pages); // Return the largest page size that can be used static size_t max_page_size() { diff --git a/hotspot/src/share/vm/runtime/virtualspace.cpp b/hotspot/src/share/vm/runtime/virtualspace.cpp index b659ec5eb06..d57f1be3973 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.cpp +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp @@ -38,7 +38,8 @@ ReservedSpace::ReservedSpace() : _base(NULL), _size(0), _noaccess_prefix(0), } ReservedSpace::ReservedSpace(size_t size) { - size_t page_size = os::page_size_for_region(size, 1); + // Want to use large pages where possible and pad with small pages. + size_t page_size = os::page_size_for_region_unaligned(size, 1); bool large_pages = page_size != (size_t)os::vm_page_size(); // Don't force the alignment to be large page aligned, // since that will waste memory. @@ -617,7 +618,7 @@ VirtualSpace::VirtualSpace() { bool VirtualSpace::initialize(ReservedSpace rs, size_t committed_size) { - const size_t max_commit_granularity = os::page_size_for_region(rs.size(), 1); + const size_t max_commit_granularity = os::page_size_for_region_unaligned(rs.size(), 1); return initialize_with_granularity(rs, committed_size, max_commit_granularity); } @@ -1239,7 +1240,7 @@ class TestVirtualSpace : AllStatic { case Disable: return vs.initialize_with_granularity(rs, 0, os::vm_page_size()); case Commit: - return vs.initialize_with_granularity(rs, 0, os::page_size_for_region(rs.size(), 1)); + return vs.initialize_with_granularity(rs, 0, os::page_size_for_region_unaligned(rs.size(), 1)); } } From 427f25366eb336d3e6c4d0e511f600e40ecd4ac6 Mon Sep 17 00:00:00 2001 From: Dmitrij Pochepko Date: Fri, 16 Jan 2015 20:59:23 +0400 Subject: [PATCH 16/72] 8068385: [TESTBUG] hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java sometimes fails(unstable behaviour) Fixing unstable behaviour of 2 tests Reviewed-by: iignatyev --- .../codecache/jmx/PoolsIndependenceTest.java | 12 +++++++----- .../codecache/jmx/ThresholdNotificationsTest.java | 4 +++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java b/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java index 04551a2d2df..8e390c1d70d 100644 --- a/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java +++ b/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java @@ -98,11 +98,13 @@ public class PoolsIndependenceTest implements NotificationListener { return false; }); for (BlobType bt : BlobType.getAvailable()) { - int expectedNotificationsAmount = bt.equals(btype) ? 1 : 0; - Asserts.assertEQ(counters.get(bt.getMemoryPool().getName()).get(), - expectedNotificationsAmount, String.format("Unexpected " - + "amount of notifications for pool: %s", - bt.getMemoryPool().getName())); + if (CodeCacheUtils.isCodeHeapPredictable(bt)) { + int expectedNotificationsAmount = bt.equals(btype) ? 1 : 0; + Asserts.assertEQ(counters.get(bt.getMemoryPool().getName()).get(), + expectedNotificationsAmount, String.format("Unexpected " + + "amount of notifications for pool: %s", + bt.getMemoryPool().getName())); + } } try { ((NotificationEmitter) ManagementFactory.getMemoryMXBean()). diff --git a/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java b/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java index b03fbc2f4a7..fea786ebe1a 100644 --- a/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java +++ b/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java @@ -52,7 +52,9 @@ public class ThresholdNotificationsTest implements NotificationListener { public static void main(String[] args) { for (BlobType bt : BlobType.getAvailable()) { - new ThresholdNotificationsTest(bt).runTest(); + if (CodeCacheUtils.isCodeHeapPredictable(bt)) { + new ThresholdNotificationsTest(bt).runTest(); + } } } From 0b17d19f488958195d41e89b2ceda9f04a647a2b Mon Sep 17 00:00:00 2001 From: Pavel Chistyakov Date: Fri, 16 Jan 2015 15:08:20 +0300 Subject: [PATCH 17/72] 8068231: Several tests are still excluded Reviewed-by: kvn, iignatyev --- hotspot/test/compiler/loopopts/7052494/Test7052494.java | 1 - 1 file changed, 1 deletion(-) diff --git a/hotspot/test/compiler/loopopts/7052494/Test7052494.java b/hotspot/test/compiler/loopopts/7052494/Test7052494.java index fa454112b6d..62aa12fc427 100644 --- a/hotspot/test/compiler/loopopts/7052494/Test7052494.java +++ b/hotspot/test/compiler/loopopts/7052494/Test7052494.java @@ -25,7 +25,6 @@ /** * @test * @bug 7052494 - * @ignore 7154567 * @summary Eclipse test fails on JDK 7 b142 * * @run main/othervm -Xbatch Test7052494 From 0520df8a92404becac0f319ba59158e50dca112c Mon Sep 17 00:00:00 2001 From: Axel Siebenborn Date: Fri, 16 Jan 2015 13:58:22 +0100 Subject: [PATCH 18/72] 8068909: SIGSEGV in c2 compiled code with OptimizeStringConcat Reviewed-by: kvn --- hotspot/src/share/vm/opto/stringopts.cpp | 11 ++- .../stringopts/TestOptimizeStringConcat.java | 89 +++++++++++++++++++ 2 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 hotspot/test/compiler/stringopts/TestOptimizeStringConcat.java diff --git a/hotspot/src/share/vm/opto/stringopts.cpp b/hotspot/src/share/vm/opto/stringopts.cpp index 1d9bae5a6ac..5f7da1f8c74 100644 --- a/hotspot/src/share/vm/opto/stringopts.cpp +++ b/hotspot/src/share/vm/opto/stringopts.cpp @@ -1507,10 +1507,12 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) { } case StringConcat::StringMode: { const Type* type = kit.gvn().type(arg); + Node* count = NULL; if (type == TypePtr::NULL_PTR) { // replace the argument with the null checked version arg = null_string; sc->set_argument(argi, arg); + count = kit.load_String_length(kit.control(), arg); } else if (!type->higher_equal(TypeInstPtr::NOTNULL)) { // s = s != null ? s : "null"; // length = length + (s.count - s.offset); @@ -1533,10 +1535,13 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) { // replace the argument with the null checked version arg = phi; sc->set_argument(argi, arg); + count = kit.load_String_length(kit.control(), arg); + } else { + // A corresponding nullcheck will be connected during IGVN MemNode::Ideal_common_DU_postCCP + // kit.control might be a different test, that can be hoisted above the actual nullcheck + // in case, that the control input is not null, Ideal_common_DU_postCCP will not look for a nullcheck. + count = kit.load_String_length(NULL, arg); } - - Node* count = kit.load_String_length(kit.control(), arg); - length = __ AddI(length, count); string_sizes->init_req(argi, NULL); break; diff --git a/hotspot/test/compiler/stringopts/TestOptimizeStringConcat.java b/hotspot/test/compiler/stringopts/TestOptimizeStringConcat.java new file mode 100644 index 00000000000..771ffb0bd68 --- /dev/null +++ b/hotspot/test/compiler/stringopts/TestOptimizeStringConcat.java @@ -0,0 +1,89 @@ +/* + * Copyright 2015 SAP AG. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8068909 + * @key regression + * @summary test that string optimizations produce code, that doesn't lead to a crash. + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestOptimizeStringConcat + * @author axel.siebenborn@sap.com + */ +public class TestOptimizeStringConcat { + + static boolean checkArgumentSyntax(String value, String allowedchars, String notallowedchars, String logmsg) { + String rc = null; + + int maxchar = 99999; + int minchar = 1; + if ((allowedchars != null && notallowedchars != null) || minchar > maxchar) { + rc = "internal error"; + } else { + if (value == null) { + rc = "the value null is not allowed, it is missing"; + } else if (value != null && minchar > 0 && value.trim().equals("")) { + rc = "the value must not be empty"; + } else if (value != null) { + if (value.length() < minchar || value.length() > maxchar) { + if (rc == null) { + rc = "the value length must be between +minchar+ and +maxchar"; + } + } + char[] _value = value.toCharArray(); + boolean dotfound = false; + int i = 1; + if (_value[i] == '.' && !dotfound) { + dotfound = true; + } else if (allowedchars != null && allowedchars.indexOf(_value[i]) == -1) { + if (rc == null) { + rc = "the value contains an illegal character: '" + _value[i] + "', only following characters are allowed: '+allowedchars+'"; + } else { + rc += " / the value contains an illegal character: '" + _value[i] + "', only following characters are allowed: '+allowedchars+'"; + } + } else if (notallowedchars != null && notallowedchars.indexOf(_value[i]) != -1) { + if (rc == null) { + rc = "the value contains an illegal character: '" + _value[i] + "', following characters are not allowed '+notallowedchars+'"; + } else { + rc += " / the value contains an illegal character: '" + _value[i] + "', following characters are not allowed '+notallowedchars+'"; + } + } + } + } + + if (rc != null) { + System.out.println(logmsg + " ==> " + rc); + return false; + } + return true; + } + + public static void main(String[] args) { + boolean failed = false; + for (int i = 0; i < 10000; i++) { + failed |= !checkArgumentSyntax("theName", null, "\"<&", "Error consistencyCheck: name in component definition"); + failed |= !checkArgumentSyntax(null, null, "\"<&", "Error consistencyCheck: name in component definition"); + failed |= !checkArgumentSyntax("42", "0123456789.", null, "Error consistencyCheck: counter in component definition"); + } + System.out.println(failed); + } +} From 759740976be0bb7da8f3f4a7491cca7055201dfb Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Fri, 16 Jan 2015 14:43:45 +0100 Subject: [PATCH 19/72] 8068971: A heap region being cleared should not belong to the cset Reviewed-by: brutisso, tschatzl --- hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 5ead54b16a5..d5eaf9f8da3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -162,8 +162,8 @@ void HeapRegion::hr_clear(bool par, bool clear_space, bool locked) { "we should have already filtered out humongous regions"); assert(_end == orig_end(), "we should have already filtered out humongous regions"); - - _in_collection_set = false; + assert(!_in_collection_set, + err_msg("Should not clear heap region %u in the collection set", hrm_index())); set_allocation_context(AllocationContext::system()); set_young_index_in_cset(-1); From 3d112a8dc36a5d34366cefddca729ac97de1b20e Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Fri, 16 Jan 2015 21:28:02 +0000 Subject: [PATCH 20/72] 8035938: Memory leak in JvmtiEnv::GetConstantPool Reviewed-by: sspitsyn, dcubed --- hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp b/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp index be0536630cb..b0c5a4325d9 100644 --- a/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp +++ b/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp @@ -68,11 +68,11 @@ class JvmtiConstantPoolReconstituter : public StackObj { ~JvmtiConstantPoolReconstituter() { if (_symmap != NULL) { - os::free(_symmap); + delete _symmap; _symmap = NULL; } if (_classmap != NULL) { - os::free(_classmap); + delete _classmap; _classmap = NULL; } } From eb5be4c2fe58e98b67d1da360d45ec8f9725f44c Mon Sep 17 00:00:00 2001 From: Zoltan Majo Date: Mon, 19 Jan 2015 09:32:40 +0100 Subject: [PATCH 21/72] 8066312: Add new Node* Node::find_out(int opc) method Added methods find_user_with() and has_user_with() for searching for a particular out type. Reviewed-by: kvn, jrose --- hotspot/src/share/vm/opto/escape.cpp | 36 ++++++--------------------- hotspot/src/share/vm/opto/ifg.cpp | 8 ++---- hotspot/src/share/vm/opto/macro.cpp | 9 +------ hotspot/src/share/vm/opto/memnode.cpp | 1 - hotspot/src/share/vm/opto/node.cpp | 28 +++++++++++++++++++++ hotspot/src/share/vm/opto/node.hpp | 36 +++++++++++++++++++-------- 6 files changed, 63 insertions(+), 55 deletions(-) diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index 736248113c7..42ba1262000 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -2010,14 +2010,9 @@ bool ConnectionGraph::is_oop_field(Node* n, int offset, bool* unsafe) { bt = field->layout_type(); } else { // Check for unsafe oop field access - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - int opcode = n->fast_out(i)->Opcode(); - if (opcode == Op_StoreP || opcode == Op_LoadP || - opcode == Op_StoreN || opcode == Op_LoadN) { - bt = T_OBJECT; - (*unsafe) = true; - break; - } + if (n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN)) { + bt = T_OBJECT; + (*unsafe) = true; } } } else if (adr_type->isa_aryptr()) { @@ -2031,13 +2026,8 @@ bool ConnectionGraph::is_oop_field(Node* n, int offset, bool* unsafe) { } } else if (adr_type->isa_rawptr() || adr_type->isa_klassptr()) { // Allocation initialization, ThreadLocal field access, unsafe access - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - int opcode = n->fast_out(i)->Opcode(); - if (opcode == Op_StoreP || opcode == Op_LoadP || - opcode == Op_StoreN || opcode == Op_LoadN) { - bt = T_OBJECT; - break; - } + if (n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN)) { + bt = T_OBJECT; } } } @@ -3092,13 +3082,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) continue; } else if (n->Opcode() == Op_EncodeISOArray) { // get the memory projection - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - Node *use = n->fast_out(i); - if (use->Opcode() == Op_SCMemProj) { - n = use; - break; - } - } + n = n->find_out_with(Op_SCMemProj); assert(n->Opcode() == Op_SCMemProj, "memory projection required"); } else { assert(n->is_Mem(), "memory node required."); @@ -3122,13 +3106,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist) continue; // don't push users } else if (n->is_LoadStore()) { // get the memory projection - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - Node *use = n->fast_out(i); - if (use->Opcode() == Op_SCMemProj) { - n = use; - break; - } - } + n = n->find_out_with(Op_SCMemProj); assert(n->Opcode() == Op_SCMemProj, "memory projection required"); } } diff --git a/hotspot/src/share/vm/opto/ifg.cpp b/hotspot/src/share/vm/opto/ifg.cpp index 61e13439637..f01cd40f7c9 100644 --- a/hotspot/src/share/vm/opto/ifg.cpp +++ b/hotspot/src/share/vm/opto/ifg.cpp @@ -535,12 +535,8 @@ bool PhaseChaitin::remove_node_if_not_used(Block* b, uint location, Node* n, uin // The method add_input_to_liveout() keeps such nodes alive (put them on liveout list) // when it sees SCMemProj node in a block. Unfortunately SCMemProj node could be placed // in block in such order that KILL MachProj nodes are processed first. - uint cnt = def->outcnt(); - for (uint i = 0; i < cnt; i++) { - Node* proj = def->raw_out(i); - if (proj->Opcode() == Op_SCMemProj) { - return false; - } + if (def->has_out_with(Op_SCMemProj)) { + return false; } } b->remove_node(location); diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index b393745620b..93659c32ad4 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -258,14 +258,7 @@ void PhaseMacroExpand::eliminate_card_mark(Node* p2x) { // Search for CastP2X->Xor->URShift->Cmp path which // checks if the store done to a different from the value's region. // And replace Cmp with #0 (false) to collapse G1 post barrier. - Node* xorx = NULL; - for (DUIterator_Fast imax, i = p2x->fast_outs(imax); i < imax; i++) { - Node* u = p2x->fast_out(i); - if (u->Opcode() == Op_XorX) { - xorx = u; - break; - } - } + Node* xorx = p2x->find_out_with(Op_XorX); assert(xorx != NULL, "missing G1 post barrier"); Node* shift = xorx->unique_out(); Node* cmpx = shift->unique_out(); diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 966bcbeb0f7..3afa49c4495 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -2609,7 +2609,6 @@ bool StoreNode::value_never_loaded( PhaseTransform *phase) const { return false; // if not a distinct instance, there may be aliases of the address for (DUIterator_Fast imax, i = adr->fast_outs(imax); i < imax; i++) { Node *use = adr->fast_out(i); - int opc = use->Opcode(); if (use->is_Load() || use->is_LoadStore()) { return false; } diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp index 8ed950a021e..225b20c55dd 100644 --- a/hotspot/src/share/vm/opto/node.cpp +++ b/hotspot/src/share/vm/opto/node.cpp @@ -881,6 +881,34 @@ Node* Node::uncast() const { return (Node*) this; } +// Find out of current node that matches opcode. +Node* Node::find_out_with(int opcode) { + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + Node* use = fast_out(i); + if (use->Opcode() == opcode) { + return use; + } + } + return NULL; +} + +// Return true if the current node has an out that matches opcode. +bool Node::has_out_with(int opcode) { + return (find_out_with(opcode) != NULL); +} + +// Return true if the current node has an out that matches any of the opcodes. +bool Node::has_out_with(int opcode1, int opcode2, int opcode3, int opcode4) { + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + int opcode = fast_out(i)->Opcode(); + if (opcode == opcode1 || opcode == opcode2 || opcode == opcode3 || opcode == opcode4) { + return true; + } + } + return false; +} + + //---------------------------uncast_helper------------------------------------- Node* Node::uncast_helper(const Node* p) { #ifdef ASSERT diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index bcf6911df52..5361a8bc4c8 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -436,6 +436,13 @@ protected: return (this->uncast() == n->uncast()); } + // Find out of current node that matches opcode. + Node* find_out_with(int opcode); + // Return true if the current node has an out that matches opcode. + bool has_out_with(int opcode); + // Return true if the current node has an out that matches any of the opcodes. + bool has_out_with(int opcode1, int opcode2, int opcode3, int opcode4); + private: static Node* uncast_helper(const Node* n); @@ -507,18 +514,25 @@ public: //----------------- Other Node Properties - // Generate class id for some ideal nodes to avoid virtual query - // methods is_(). - // Class id is the set of bits corresponded to the node class and all its - // super classes so that queries for super classes are also valid. - // Subclasses of the same super class have different assigned bit - // (the third parameter in the macro DEFINE_CLASS_ID). - // Classes with deeper hierarchy are declared first. - // Classes with the same hierarchy depth are sorted by usage frequency. + // Generate class IDs for (some) ideal nodes so that it is possible to determine + // the type of a node using a non-virtual method call (the method is_() below). // - // The query method masks the bits to cut off bits of subclasses - // and then compare the result with the class id - // (see the macro DEFINE_CLASS_QUERY below). + // A class ID of an ideal node is a set of bits. In a class ID, a single bit determines + // the type of the node the ID represents; another subset of an ID's bits are reserved + // for the superclasses of the node represented by the ID. + // + // By design, if A is a supertype of B, A.is_B() returns true and B.is_A() + // returns false. A.is_A() returns true. + // + // If two classes, A and B, have the same superclass, a different bit of A's class id + // is reserved for A's type than for B's type. That bit is specified by the third + // parameter in the macro DEFINE_CLASS_ID. + // + // By convention, classes with deeper hierarchy are declared first. Moreover, + // classes with the same hierarchy depth are sorted by usage frequency. + // + // The query method masks the bits to cut off bits of subclasses and then compares + // the result with the class id (see the macro DEFINE_CLASS_QUERY below). // // Class_MachCall=30, ClassMask_MachCall=31 // 12 8 4 0 From 878f630fe00746bc951da6093a7552fd2924c9ab Mon Sep 17 00:00:00 2001 From: Ivan Gerasimov Date: Mon, 19 Jan 2015 11:35:15 +0300 Subject: [PATCH 22/72] 8069048: (process) Suspend finishing threads when process exits [win] Reviewed-by: dholmes, dcubed --- hotspot/src/os/windows/vm/os_windows.cpp | 33 ++++++++++++++---------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index fb09815cf79..f8f17d556d0 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -428,9 +428,9 @@ static unsigned __stdcall java_start(Thread* thread) { } // Diagnostic code to investigate JDK-6573254 - int res = 50115; // non-java thread + int res = 30115; // non-java thread if (thread->is_Java_thread()) { - res = 40115; // java thread + res = 20115; // java thread } // Install a win32 structured exception handler around every thread created @@ -3791,6 +3791,7 @@ int os::win32::exit_process_or_thread(Ept what, int exit_code) { static INIT_ONCE init_once_crit_sect = INIT_ONCE_STATIC_INIT; static CRITICAL_SECTION crit_sect; + static volatile jint process_exiting = 0; int i, j; DWORD res; HANDLE hproc, hthr; @@ -3798,10 +3799,10 @@ int os::win32::exit_process_or_thread(Ept what, int exit_code) { // The first thread that reached this point, initializes the critical section. if (!InitOnceExecuteOnce(&init_once_crit_sect, init_crit_sect_call, &crit_sect, NULL)) { warning("crit_sect initialization failed in %s: %d\n", __FILE__, __LINE__); - } else { + } else if (OrderAccess::load_acquire(&process_exiting) == 0) { EnterCriticalSection(&crit_sect); - if (what == EPT_THREAD) { + if (what == EPT_THREAD && OrderAccess::load_acquire(&process_exiting) == 0) { // Remove from the array those handles of the threads that have completed exiting. for (i = 0, j = 0; i < handle_count; ++i) { res = WaitForSingleObject(handles[i], 0 /* don't wait */); @@ -3856,7 +3857,7 @@ int os::win32::exit_process_or_thread(Ept what, int exit_code) { // The current exiting thread has stored its handle in the array, and now // should leave the critical section before calling _endthreadex(). - } else { // what != EPT_THREAD + } else if (what != EPT_THREAD) { if (handle_count > 0) { // Before ending the process, make sure all the threads that had called // _endthreadex() completed. @@ -3882,24 +3883,28 @@ int os::win32::exit_process_or_thread(Ept what, int exit_code) { handle_count = 0; } - // End the process, not leaving critical section. - // This makes sure no other thread executes exit-related code at the same - // time, thus a race is avoided. - if (what == EPT_PROCESS) { - ::exit(exit_code); - } else { - _exit(exit_code); - } + OrderAccess::release_store(&process_exiting, 1); } LeaveCriticalSection(&crit_sect); } + + if (what == EPT_THREAD) { + while (OrderAccess::load_acquire(&process_exiting) != 0) { + // Some other thread is about to call exit(), so we + // don't let the current thread proceed to _endthreadex() + SuspendThread(GetCurrentThread()); + // Avoid busy-wait loop, if SuspendThread() failed. + Sleep(EXIT_TIMEOUT); + } + } } // We are here if either // - there's no 'race at exit' bug on this OS release; // - initialization of the critical section failed (unlikely); - // - the current thread has stored its handle and left the critical section. + // - the current thread has stored its handle and left the critical section; + // - the process-exiting thread has raised the flag and left the critical section. if (what == EPT_THREAD) { _endthreadex((unsigned)exit_code); } else if (what == EPT_PROCESS) { From d508c520f086120e407979acc52572fb60eee1af Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Mon, 19 Jan 2015 10:06:14 +0100 Subject: [PATCH 23/72] 8040935: -XX:+AggressiveOpts broken: GC triggered before VM initialization completed on several tests Reviewed-by: brutisso, kbarrett --- hotspot/test/gc/TestNUMAPageSize.java | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/test/gc/TestNUMAPageSize.java b/hotspot/test/gc/TestNUMAPageSize.java index 1a3b5ddbebf..9537f0f7ab6 100644 --- a/hotspot/test/gc/TestNUMAPageSize.java +++ b/hotspot/test/gc/TestNUMAPageSize.java @@ -25,6 +25,7 @@ * @test TestNUMAPageSize * @summary Make sure that start up with NUMA support does not cause problems. * @bug 8061467 + * @requires (vm.opt.AggressiveOpts == null) | (vm.opt.AggressiveOpts == false) * @key gc * @key regression * @run main/othervm -Xmx8M -XX:+UseNUMA TestNUMAPageSize From 3a11c1d75c7bb683424e51a7bb1a31d821c26944 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Mon, 19 Jan 2015 10:08:07 +0100 Subject: [PATCH 24/72] 8069011: gc/TestSmallHeap.java failing in nightly Using @requires to avoid running with AggressiveOpts turned on. Reviewed-by: jwilhelm, brutisso --- hotspot/test/gc/TestSmallHeap.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hotspot/test/gc/TestSmallHeap.java b/hotspot/test/gc/TestSmallHeap.java index 170b5397740..abe6ed37f98 100644 --- a/hotspot/test/gc/TestSmallHeap.java +++ b/hotspot/test/gc/TestSmallHeap.java @@ -25,6 +25,7 @@ * @test TestSmallHeap * @bug 8067438 * @requires vm.gc=="null" + * @requires (vm.opt.AggressiveOpts=="null") | (vm.opt.AggressiveOpts=="false") * @summary Verify that starting the VM with a small heap works * @library /testlibrary /../../test/lib * @build TestSmallHeap @@ -33,8 +34,9 @@ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseSerialGC TestSmallHeap * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseG1GC TestSmallHeap * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseConcMarkSweepGC TestSmallHeap - * - * Note: It would be nice to verify the minimal supported heap size (2m) here, + */ + +/* Note: It would be nice to verify the minimal supported heap size (2m) here, * but we align the heap size based on the card table size. And the card table * size is aligned based on the minimal pages size provided by the os. This * means that on most platforms, where the minimal page size is 4k, we get a From aca3a19f56dfe30459394f0d3b7c8c998b231adc Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Mon, 19 Jan 2015 12:29:50 -0800 Subject: [PATCH 25/72] 8068881: SIGBUS in C2 compiled method weblogic.wsee.jaxws.framework.jaxrpc.EnvironmentFactory$SimulatedWsdlDefinitions. Use MachMerge to hook together defs of the same multidef value in a block Reviewed-by: kvn, vlivanov --- hotspot/src/share/vm/opto/chaitin.cpp | 3 + hotspot/src/share/vm/opto/chaitin.hpp | 26 +++++++ hotspot/src/share/vm/opto/machnode.hpp | 23 ++++++ hotspot/src/share/vm/opto/node.hpp | 3 + hotspot/src/share/vm/opto/phase.cpp | 2 + hotspot/src/share/vm/opto/phase.hpp | 1 + hotspot/src/share/vm/opto/postaloc.cpp | 102 +++++++++++++++++++++---- 7 files changed, 146 insertions(+), 14 deletions(-) diff --git a/hotspot/src/share/vm/opto/chaitin.cpp b/hotspot/src/share/vm/opto/chaitin.cpp index c03c0f4052e..106e22879b7 100644 --- a/hotspot/src/share/vm/opto/chaitin.cpp +++ b/hotspot/src/share/vm/opto/chaitin.cpp @@ -582,6 +582,9 @@ void PhaseChaitin::Register_Allocate() { // Peephole remove copies post_allocate_copy_removal(); + // Merge multidefs if multiple defs representing the same value are used in a single block. + merge_multidefs(); + #ifdef ASSERT // Veify the graph after RA. verify(&live_arena); diff --git a/hotspot/src/share/vm/opto/chaitin.hpp b/hotspot/src/share/vm/opto/chaitin.hpp index 99194cfe925..51915c52133 100644 --- a/hotspot/src/share/vm/opto/chaitin.hpp +++ b/hotspot/src/share/vm/opto/chaitin.hpp @@ -681,6 +681,32 @@ private: // Extend the node to LRG mapping void add_reference( const Node *node, const Node *old_node); + // Record the first use of a def in the block for a register. + class RegDefUse { + Node* _def; + Node* _first_use; + public: + RegDefUse() : _def(NULL), _first_use(NULL) { } + Node* def() const { return _def; } + Node* first_use() const { return _first_use; } + + void update(Node* def, Node* use) { + if (_def != def) { + _def = def; + _first_use = use; + } + } + void clear() { + _def = NULL; + _first_use = NULL; + } + }; + typedef GrowableArray RegToDefUseMap; + int possibly_merge_multidef(Node *n, uint k, Block *block, RegToDefUseMap& reg2defuse); + + // Merge nodes that are a part of a multidef lrg and produce the same value within a block. + void merge_multidefs(); + private: static int _final_loads, _final_stores, _final_copies, _final_memoves; diff --git a/hotspot/src/share/vm/opto/machnode.hpp b/hotspot/src/share/vm/opto/machnode.hpp index a557c02e6c6..e30e23406c6 100644 --- a/hotspot/src/share/vm/opto/machnode.hpp +++ b/hotspot/src/share/vm/opto/machnode.hpp @@ -616,6 +616,29 @@ public: #endif }; +// MachMergeNode is similar to a PhiNode in a sense it merges multiple values, +// however it doesn't have a control input and is more like a MergeMem. +// It is inserted after the register allocation is done to ensure that nodes use single +// definition of a multidef lrg in a block. +class MachMergeNode : public MachIdealNode { +public: + MachMergeNode(Node *n1) { + init_class_id(Class_MachMerge); + add_req(NULL); + add_req(n1); + } + virtual const RegMask &out_RegMask() const { return in(1)->out_RegMask(); } + virtual const RegMask &in_RegMask(uint idx) const { return in(1)->in_RegMask(idx); } + virtual const class Type *bottom_type() const { return in(1)->bottom_type(); } + virtual uint ideal_reg() const { return bottom_type()->ideal_reg(); } + virtual uint oper_input_base() const { return 1; } + virtual void emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { } + virtual uint size(PhaseRegAlloc *ra_) const { return 0; } +#ifndef PRODUCT + virtual const char *Name() const { return "MachMerge"; } +#endif +}; + //------------------------------MachBranchNode-------------------------------- // Abstract machine branch Node class MachBranchNode : public MachIdealNode { diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index 5361a8bc4c8..ce591dce482 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -98,6 +98,7 @@ class MachReturnNode; class MachSafePointNode; class MachSpillCopyNode; class MachTempNode; +class MachMergeNode; class Matcher; class MemBarNode; class MemBarStoreStoreNode; @@ -606,6 +607,7 @@ public: DEFINE_CLASS_ID(MachTemp, Mach, 3) DEFINE_CLASS_ID(MachConstantBase, Mach, 4) DEFINE_CLASS_ID(MachConstant, Mach, 5) + DEFINE_CLASS_ID(MachMerge, Mach, 6) DEFINE_CLASS_ID(Type, Node, 2) DEFINE_CLASS_ID(Phi, Type, 0) @@ -777,6 +779,7 @@ public: DEFINE_CLASS_QUERY(MachSafePoint) DEFINE_CLASS_QUERY(MachSpillCopy) DEFINE_CLASS_QUERY(MachTemp) + DEFINE_CLASS_QUERY(MachMerge) DEFINE_CLASS_QUERY(Mem) DEFINE_CLASS_QUERY(MemBar) DEFINE_CLASS_QUERY(MemBarStoreStore) diff --git a/hotspot/src/share/vm/opto/phase.cpp b/hotspot/src/share/vm/opto/phase.cpp index 0c9c697414d..9662bbcbbfb 100644 --- a/hotspot/src/share/vm/opto/phase.cpp +++ b/hotspot/src/share/vm/opto/phase.cpp @@ -110,6 +110,7 @@ void Phase::print_timers() { tty->print_cr (" Compute Liveness: %7.3f s", timers[_t_computeLive].seconds()); tty->print_cr (" Regalloc Split: %7.3f s", timers[_t_regAllocSplit].seconds()); tty->print_cr (" Postalloc Copy Rem: %7.3f s", timers[_t_postAllocCopyRemoval].seconds()); + tty->print_cr (" Merge multidefs: %7.3f s", timers[_t_mergeMultidefs].seconds()); tty->print_cr (" Fixup Spills: %7.3f s", timers[_t_fixupSpills].seconds()); tty->print_cr (" Compact: %7.3f s", timers[_t_chaitinCompact].seconds()); tty->print_cr (" Coalesce 1: %7.3f s", timers[_t_chaitinCoalesce1].seconds()); @@ -126,6 +127,7 @@ void Phase::print_timers() { timers[_t_computeLive].seconds() + timers[_t_regAllocSplit].seconds() + timers[_t_postAllocCopyRemoval].seconds() + + timers[_t_mergeMultidefs].seconds() + timers[_t_fixupSpills].seconds() + timers[_t_chaitinCompact].seconds() + timers[_t_chaitinCoalesce1].seconds() + diff --git a/hotspot/src/share/vm/opto/phase.hpp b/hotspot/src/share/vm/opto/phase.hpp index f273947a1d9..4b5d53d1656 100644 --- a/hotspot/src/share/vm/opto/phase.hpp +++ b/hotspot/src/share/vm/opto/phase.hpp @@ -88,6 +88,7 @@ public: _t_computeLive, _t_regAllocSplit, _t_postAllocCopyRemoval, + _t_mergeMultidefs, _t_fixupSpills, _t_chaitinCompact, _t_chaitinCoalesce1, diff --git a/hotspot/src/share/vm/opto/postaloc.cpp b/hotspot/src/share/vm/opto/postaloc.cpp index 35e3974d3a1..d6ac1020266 100644 --- a/hotspot/src/share/vm/opto/postaloc.cpp +++ b/hotspot/src/share/vm/opto/postaloc.cpp @@ -263,20 +263,6 @@ int PhaseChaitin::elide_copy( Node *n, int k, Block *current_block, Node_List &v // intermediate copies might be illegal, i.e., value is stored down to stack // then reloaded BUT survives in a register the whole way. Node *val = skip_copies(n->in(k)); - - if (val == x && nk_idx != 0 && - regnd[nk_reg] != NULL && regnd[nk_reg] != x && - _lrg_map.live_range_id(x) == _lrg_map.live_range_id(regnd[nk_reg])) { - // When rematerialzing nodes and stretching lifetimes, the - // allocator will reuse the original def for multidef LRG instead - // of the current reaching def because it can't know it's safe to - // do so. After allocation completes if they are in the same LRG - // then it should use the current reaching def instead. - n->set_req(k, regnd[nk_reg]); - blk_adjust += yank_if_dead(val, current_block, &value, ®nd); - val = skip_copies(n->in(k)); - } - if (val == x) return blk_adjust; // No progress? int n_regs = RegMask::num_registers(val->ideal_reg()); @@ -382,6 +368,94 @@ bool PhaseChaitin::eliminate_copy_of_constant(Node* val, Node* n, return false; } +// The algorithms works as follows: +// We traverse the block top to bottom. possibly_merge_multidef() is invoked for every input edge k +// of the instruction n. We check to see if the input is a multidef lrg. If it is, we record the fact that we've +// seen a definition (coming as an input) and add that fact to the reg2defuse array. The array maps registers to their +// current reaching definitions (we track only multidefs though). With each definition we also associate the first +// instruction we saw use it. If we encounter the situation when we observe an def (an input) that is a part of the +// same lrg but is different from the previous seen def we merge the two with a MachMerge node and substitute +// all the uses that we've seen so far to use the merge. After that we keep replacing the new defs in the same lrg +// as they get encountered with the merge node and keep adding these defs to the merge inputs. +void PhaseChaitin::merge_multidefs() { + Compile::TracePhase tp("mergeMultidefs", &timers[_t_mergeMultidefs]); + ResourceMark rm; + // Keep track of the defs seen in registers and collect their uses in the block. + RegToDefUseMap reg2defuse(_max_reg, _max_reg, RegDefUse()); + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); + for (uint j = 1; j < block->number_of_nodes(); j++) { + Node* n = block->get_node(j); + if (n->is_Phi()) continue; + for (uint k = 1; k < n->req(); k++) { + j += possibly_merge_multidef(n, k, block, reg2defuse); + } + // Null out the value produced by the instruction itself, since we're only interested in defs + // implicitly defined by the uses. We are actually interested in tracking only redefinitions + // of the multidef lrgs in the same register. For that matter it's enough to track changes in + // the base register only and ignore other effects of multi-register lrgs and fat projections. + // It is also ok to ignore defs coming from singledefs. After an implicit overwrite by one of + // those our register is guaranteed to be used by another lrg and we won't attempt to merge it. + uint lrg = _lrg_map.live_range_id(n); + if (lrg > 0 && lrgs(lrg).is_multidef()) { + OptoReg::Name reg = lrgs(lrg).reg(); + reg2defuse.at(reg).clear(); + } + } + // Clear reg->def->use tracking for the next block + for (int j = 0; j < reg2defuse.length(); j++) { + reg2defuse.at(j).clear(); + } + } +} + +int PhaseChaitin::possibly_merge_multidef(Node *n, uint k, Block *block, RegToDefUseMap& reg2defuse) { + int blk_adjust = 0; + + uint lrg = _lrg_map.live_range_id(n->in(k)); + if (lrg > 0 && lrgs(lrg).is_multidef()) { + OptoReg::Name reg = lrgs(lrg).reg(); + + Node* def = reg2defuse.at(reg).def(); + if (def != NULL && lrg == _lrg_map.live_range_id(def) && def != n->in(k)) { + // Same lrg but different node, we have to merge. + MachMergeNode* merge; + if (def->is_MachMerge()) { // is it already a merge? + merge = def->as_MachMerge(); + } else { + merge = new MachMergeNode(def); + + // Insert the merge node into the block before the first use. + uint use_index = block->find_node(reg2defuse.at(reg).first_use()); + block->insert_node(merge, use_index++); + + // Let the allocator know about the new node, use the same lrg + _lrg_map.extend(merge->_idx, lrg); + blk_adjust++; + + // Fixup all the uses (there is at least one) that happened between the first + // use and before the current one. + for (; use_index < block->number_of_nodes(); use_index++) { + Node* use = block->get_node(use_index); + if (use == n) { + break; + } + use->replace_edge(def, merge); + } + } + if (merge->find_edge(n->in(k)) == -1) { + merge->add_req(n->in(k)); + } + n->set_req(k, merge); + } + + // update the uses + reg2defuse.at(reg).update(n->in(k), n); + } + + return blk_adjust; +} + //------------------------------post_allocate_copy_removal--------------------- // Post-Allocation peephole copy removal. We do this in 1 pass over the From 3d814126c2799aa378ab66326b7dace58860588d Mon Sep 17 00:00:00 2001 From: Zoltan Majo Date: Tue, 20 Jan 2015 09:45:11 +0100 Subject: [PATCH 26/72] 8069162: quarantine serviceability/dcmd/compiler/CompilerQueueTest.java Added '@ignore 8069160' to the test. Reviewed-by: anoll, kvn --- hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java index 1a96dd8c200..3bd7cf3ede1 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java @@ -25,6 +25,7 @@ * @test CompilerQueueTest * @bug 8054889 * @library .. + * @ignore 8069160 * @build DcmdUtil CompilerQueueTest * @run main CompilerQueueTest * @run main/othervm -XX:-TieredCompilation CompilerQueueTest From a9158e0f408bff5536c29a57af58d01b08691430 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Tue, 20 Jan 2015 13:56:35 +0100 Subject: [PATCH 27/72] 8067479: verify-modules fails in bootcycle build Reviewed-by: ihse, dholmes --- common/autoconf/bootcycle-spec.gmk.in | 7 +++++-- make/Main.gmk | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/common/autoconf/bootcycle-spec.gmk.in b/common/autoconf/bootcycle-spec.gmk.in index a547f34c951..31ff7525610 100644 --- a/common/autoconf/bootcycle-spec.gmk.in +++ b/common/autoconf/bootcycle-spec.gmk.in @@ -46,8 +46,11 @@ endif BOOT_JDK := $(JDK_IMAGE_DIR) # The bootcycle build has a different output directory -BUILD_OUTPUT:=@BUILD_OUTPUT@/bootcycle-build -SJAVAC_SERVER_DIR:=$(subst @BUILD_OUTPUT@,$(BUILD_OUTPUT),$(SJAVAC_SERVER_DIR)) +OLD_BUILD_OUTPUT:=@BUILD_OUTPUT@ +BUILD_OUTPUT:=$(OLD_BUILD_OUTPUT)/bootcycle-build +# The HOTSPOT_DIST dir is not defined relative to BUILD_OUTPUT in spec.gmk +HOTSPOT_DIST:=$(patsubst $(OLD_BUILD_OUTPUT)%, $(BUILD_OUTPUT)%, $(HOTSPOT_DIST)) +SJAVAC_SERVER_DIR:=$(patsubst $(OLD_BUILD_OUTPUT)%, $(BUILD_OUTPUT)%, $(SJAVAC_SERVER_DIR)) JAVA_CMD:=$(BOOT_JDK)/bin/java JAVAC_CMD:=$(BOOT_JDK)/bin/javac diff --git a/make/Main.gmk b/make/Main.gmk index a46f1de8508..a7af350e820 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -446,7 +446,7 @@ exploded-image: $(ALL_MODULE_TARGETS) # alias for ease of use. jdk: exploded-image -images: test-image jimages demos samples zip-security +images: test-image jimages demos samples zip-security verify-modules ifeq ($(OPENJDK_TARGET_OS), macosx) images: mac-bundles From e1bfe8762e1b8505019312814f8e229764413e6e Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Tue, 20 Jan 2015 13:56:57 +0100 Subject: [PATCH 28/72] 8067479: verify-modules fails in bootcycle build Reviewed-by: dholmes, sla --- hotspot/make/sa.files | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hotspot/make/sa.files b/hotspot/make/sa.files index fa807c36dfc..dfe1e53a209 100644 --- a/hotspot/make/sa.files +++ b/hotspot/make/sa.files @@ -39,6 +39,7 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/asm/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/asm/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/c1/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/ci/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/classfile/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/code/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/compiler/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/*.java \ @@ -49,8 +50,10 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/basic/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/dummy/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/ia64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ia64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ppc64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/sparc/*.java \ @@ -71,6 +74,7 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/win32/coff/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/ia64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windows/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windows/amd64/*.java \ @@ -101,6 +105,8 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/x86/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/win32_amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/win32_x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/ppc64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/jcore/*.java \ From e559c179548b59885ecfc43494bc12029883fc5e Mon Sep 17 00:00:00 2001 From: Zoltan Majo Date: Wed, 21 Jan 2015 10:51:35 +0100 Subject: [PATCH 29/72] 8059606: Enable per-method usage of CompileThresholdScaling (per-method compilation thresholds) Changed interpreter and compilation policies to allow using CompileThresholdScaling on a per-method level Reviewed-by: jrose, kvn --- .../src/cpu/sparc/vm/interp_masm_sparc.cpp | 21 +++--- .../src/cpu/sparc/vm/interp_masm_sparc.hpp | 6 +- .../sparc/vm/templateInterpreter_sparc.cpp | 27 +++---- .../src/cpu/sparc/vm/templateTable_sparc.cpp | 20 +++--- hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp | 2 +- hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp | 2 +- hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp | 2 +- hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp | 2 +- .../cpu/x86/vm/templateInterpreter_x86_32.cpp | 15 ++-- .../cpu/x86/vm/templateInterpreter_x86_64.cpp | 11 +-- .../src/cpu/x86/vm/templateTable_x86_32.cpp | 14 ++-- .../src/cpu/x86/vm/templateTable_x86_64.cpp | 14 ++-- hotspot/src/share/vm/c1/c1_LIRGenerator.cpp | 14 +++- .../src/share/vm/compiler/compileBroker.cpp | 4 +- .../vm/interpreter/bytecodeInterpreter.cpp | 2 +- .../vm/interpreter/invocationCounter.hpp | 4 +- hotspot/src/share/vm/oops/method.cpp | 5 +- hotspot/src/share/vm/oops/methodCounters.cpp | 7 +- hotspot/src/share/vm/oops/methodCounters.hpp | 63 +++++++++++++--- hotspot/src/share/vm/oops/methodData.cpp | 8 +++ hotspot/src/share/vm/oops/methodData.hpp | 11 +++ .../vm/runtime/advancedThresholdPolicy.cpp | 22 +++--- .../vm/runtime/advancedThresholdPolicy.hpp | 12 ++-- hotspot/src/share/vm/runtime/arguments.cpp | 72 ++++++++++++------- hotspot/src/share/vm/runtime/arguments.hpp | 15 +++- hotspot/src/share/vm/runtime/globals.hpp | 13 +++- .../vm/runtime/simpleThresholdPolicy.cpp | 20 +++--- .../vm/runtime/simpleThresholdPolicy.hpp | 10 +-- .../runtime/simpleThresholdPolicy.inline.hpp | 14 +++- hotspot/src/share/vm/runtime/vmStructs.cpp | 7 ++ .../share/vm/utilities/globalDefinitions.hpp | 9 +-- .../CheckCompileThresholdScaling.java | 2 +- 32 files changed, 293 insertions(+), 157 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp index 51f237ba626..153bfbdda55 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp @@ -1374,6 +1374,7 @@ void InterpreterMacroAssembler::verify_method_data_pointer() { } void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count, + Register method_counters, Register Rtmp, Label &profile_continue) { assert(ProfileInterpreter, "must be profiling interpreter"); @@ -1386,9 +1387,8 @@ void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocat br_notnull_short(ImethodDataPtr, Assembler::pn, done); // Test to see if we should create a method data oop - AddressLiteral profile_limit((address) &InvocationCounter::InterpreterProfileLimit); - sethi(profile_limit, Rtmp); - ld(Rtmp, profile_limit.low10(), Rtmp); + Address profile_limit(method_counters, MethodCounters::interpreter_profile_limit_offset()); + ld(profile_limit, Rtmp); cmp(invocation_count, Rtmp); // Use long branches because call_VM() code and following code generated by // test_backedge_count_for_osr() is large in debug VM. @@ -2375,6 +2375,7 @@ void InterpreterMacroAssembler::increment_backedge_counter( Register Rcounters, #ifndef CC_INTERP void InterpreterMacroAssembler::test_backedge_count_for_osr( Register backedge_count, + Register method_counters, Register branch_bcp, Register Rtmp ) { Label did_not_overflow; @@ -2382,8 +2383,8 @@ void InterpreterMacroAssembler::test_backedge_count_for_osr( Register backedge_c assert_different_registers(backedge_count, Rtmp, branch_bcp); assert(UseOnStackReplacement,"Must UseOnStackReplacement to test_backedge_count_for_osr"); - AddressLiteral limit(&InvocationCounter::InterpreterBackwardBranchLimit); - load_contents(limit, Rtmp); + Address limit(method_counters, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset())); + ld(limit, Rtmp); cmp_and_br_short(backedge_count, Rtmp, Assembler::lessUnsigned, Assembler::pt, did_not_overflow); // When ProfileInterpreter is on, the backedge_count comes from the @@ -2500,17 +2501,13 @@ void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { // Jump if ((*counter_addr += increment) & mask) satisfies the condition. void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask_addr, Register scratch1, Register scratch2, Condition cond, Label *where) { ld(counter_addr, scratch1); add(scratch1, increment, scratch1); - if (is_simm13(mask)) { - andcc(scratch1, mask, G0); - } else { - set(mask, scratch2); - andcc(scratch1, scratch2, G0); - } + ld(mask_addr, scratch2); + andcc(scratch1, scratch2, G0); br(cond, false, Assembler::pn, *where); delayed()->st(scratch1, counter_addr); } diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp index 5ba547d2241..862611c4252 100644 --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp @@ -267,7 +267,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void increment_invocation_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); void increment_backedge_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); #ifndef CC_INTERP - void test_backedge_count_for_osr( Register backedge_count, Register branch_bcp, Register Rtmp ); + void test_backedge_count_for_osr(Register backedge_count, Register method_counters, Register branch_bcp, Register Rtmp ); #endif /* CC_INTERP */ // Object locking @@ -280,7 +280,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void set_method_data_pointer_for_bcp(); void test_method_data_pointer(Label& zero_continue); void verify_method_data_pointer(); - void test_invocation_counter_for_mdp(Register invocation_count, Register Rtmp, Label &profile_continue); + void test_invocation_counter_for_mdp(Register invocation_count, Register method_counters, Register Rtmp, Label &profile_continue); void set_mdp_data_at(int constant, Register value); void increment_mdp_data_at(Address counter, Register bumped_count, @@ -291,7 +291,7 @@ class InterpreterMacroAssembler: public MacroAssembler { Register bumped_count, Register scratch2, bool decrement = false); void increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask_addr, Register scratch1, Register scratch2, Condition cond, Label *where); void set_mdp_flag_at(int flag_constant, Register scratch); diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index 93f87807482..c3039d51337 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -282,12 +282,11 @@ address TemplateInterpreterGenerator::generate_continuation_for(TosState state) void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { // Note: In tiered we increment either counters in MethodCounters* or in // MDO depending if we're profiling or not. - const Register Rcounters = G3_scratch; + const Register G3_method_counters = G3_scratch; Label done; if (TieredCompilation) { const int increment = InvocationCounter::count_increment; - const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { // If no method data exists, go to profile_continue. @@ -297,6 +296,7 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile Address mdo_invocation_counter(G4_scratch, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + Address mask(G4_scratch, in_bytes(MethodData::invoke_mask_offset())); __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, G3_scratch, Lscratch, Assembler::zero, overflow); @@ -305,20 +305,21 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile // Increment counter in MethodCounters* __ bind(no_mdo); - Address invocation_counter(Rcounters, + Address invocation_counter(G3_method_counters, in_bytes(MethodCounters::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); - __ get_method_counters(Lmethod, Rcounters, done); + __ get_method_counters(Lmethod, G3_method_counters, done); + Address mask(G3_method_counters, in_bytes(MethodCounters::invoke_mask_offset())); __ increment_mask_and_jump(invocation_counter, increment, mask, G4_scratch, Lscratch, Assembler::zero, overflow); __ bind(done); - } else { + } else { // not TieredCompilation // Update standard invocation counters - __ get_method_counters(Lmethod, Rcounters, done); - __ increment_invocation_counter(Rcounters, O0, G4_scratch); + __ get_method_counters(Lmethod, G3_method_counters, done); + __ increment_invocation_counter(G3_method_counters, O0, G4_scratch); if (ProfileInterpreter) { - Address interpreter_invocation_counter(Rcounters, + Address interpreter_invocation_counter(G3_method_counters, in_bytes(MethodCounters::interpreter_invocation_counter_offset())); __ ld(interpreter_invocation_counter, G4_scratch); __ inc(G4_scratch); @@ -327,16 +328,16 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile if (ProfileInterpreter && profile_method != NULL) { // Test to see if we should create a method data oop - AddressLiteral profile_limit((address)&InvocationCounter::InterpreterProfileLimit); - __ load_contents(profile_limit, G3_scratch); - __ cmp_and_br_short(O0, G3_scratch, Assembler::lessUnsigned, Assembler::pn, *profile_method_continue); + Address profile_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_profile_limit_offset())); + __ ld(profile_limit, G1_scratch); + __ cmp_and_br_short(O0, G1_scratch, Assembler::lessUnsigned, Assembler::pn, *profile_method_continue); // if no method data exists, go to profile_method __ test_method_data_pointer(*profile_method); } - AddressLiteral invocation_limit((address)&InvocationCounter::InterpreterInvocationLimit); - __ load_contents(invocation_limit, G3_scratch); + Address invocation_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_invocation_limit_offset())); + __ ld(invocation_limit, G3_scratch); __ cmp(O0, G3_scratch); __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); // Far distance __ delayed()->nop(); diff --git a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp index 9424b1be1f6..438d376b2c6 100644 --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp @@ -1599,13 +1599,12 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Bump bytecode pointer by displacement (take the branch) __ delayed()->add( O1_disp, Lbcp, Lbcp ); // add to bc addr - const Register Rcounters = G3_scratch; - __ get_method_counters(Lmethod, Rcounters, Lforward); + const Register G3_method_counters = G3_scratch; + __ get_method_counters(Lmethod, G3_method_counters, Lforward); if (TieredCompilation) { Label Lno_mdo, Loverflow; int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { // If no method data exists, go to profile_continue. __ ld_ptr(Lmethod, Method::method_data_offset(), G4_scratch); @@ -1614,6 +1613,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Increment backedge counter in the MDO Address mdo_backedge_counter(G4_scratch, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + Address mask(G4_scratch, in_bytes(MethodData::backedge_mask_offset())); __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, G3_scratch, O0, Assembler::notZero, &Lforward); __ ba_short(Loverflow); @@ -1621,9 +1621,10 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // If there's no MDO, increment counter in MethodCounters* __ bind(Lno_mdo); - Address backedge_counter(Rcounters, + Address backedge_counter(G3_method_counters, in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + Address mask(G3_method_counters, in_bytes(MethodCounters::backedge_mask_offset())); __ increment_mask_and_jump(backedge_counter, increment, mask, G4_scratch, O0, Assembler::notZero, &Lforward); __ bind(Loverflow); @@ -1663,18 +1664,19 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ jmp(O2, G0); __ delayed()->nop(); - } else { + } else { // not TieredCompilation // Update Backedge branch separately from invocations const Register G4_invoke_ctr = G4; - __ increment_backedge_counter(Rcounters, G4_invoke_ctr, G1_scratch); + __ increment_backedge_counter(G3_method_counters, G4_invoke_ctr, G1_scratch); if (ProfileInterpreter) { - __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_scratch, Lforward); + __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_method_counters, G1_scratch, Lforward); if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(O2_bumped_count, l_cur_bcp, G3_scratch); + + __ test_backedge_count_for_osr(O2_bumped_count, G3_method_counters, l_cur_bcp, G1_scratch); } } else { if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(G4_invoke_ctr, l_cur_bcp, G3_scratch); + __ test_backedge_count_for_osr(G4_invoke_ctr, G3_method_counters, l_cur_bcp, G1_scratch); } } } diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp index 181ee15251b..9aa4587f793 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp @@ -1360,7 +1360,7 @@ void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { // Jump if ((*counter_addr += increment) & mask) satisfies the condition. void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where) { if (!preloaded) { diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp index e4d61364de4..2cd8e162fde 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp @@ -182,7 +182,7 @@ void increment_mdp_data_at(Register mdp_in, Register reg, int constant, bool decrement = false); void increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where); void set_mdp_flag_at(Register mdp_in, int flag_constant); diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp index 23e3b973041..76335ca9fcc 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp @@ -1426,7 +1426,7 @@ void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { // Jump if ((*counter_addr += increment) & mask) satisfies the condition. void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where) { if (!preloaded) { diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp index a1cd4466bb9..c4ed238bc20 100644 --- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp @@ -191,7 +191,7 @@ void increment_mdp_data_at(Register mdp_in, Register reg, int constant, bool decrement = false); void increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where); void set_mdp_flag_at(Register mdp_in, int flag_constant); diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp index 93772f3df4c..69c8533d12e 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp @@ -346,7 +346,6 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile // depending if we're profiling or not. if (TieredCompilation) { int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { // Are we profiling? @@ -356,6 +355,7 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile // Increment counter in the MDO const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rax, in_bytes(MethodData::invoke_mask_offset())); __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ jmp(done); } @@ -366,11 +366,12 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile InvocationCounter::counter_offset()); __ get_method_counters(rbx, rax, done); + const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset())); __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ bind(done); - } else { - const Address backedge_counter (rax, + } else { // not TieredCompilation + const Address backedge_counter(rax, MethodCounters::backedge_counter_offset() + InvocationCounter::counter_offset()); const Address invocation_counter(rax, @@ -400,16 +401,16 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile if (ProfileInterpreter && profile_method != NULL) { // Test to see if we should create a method data oop - __ cmp32(rcx, - ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, *profile_method_continue); // if no method data exists, go to profile_method __ test_method_data_pointer(rax, *profile_method); } - __ cmp32(rcx, - ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_invocation_limit_offset()))); __ jcc(Assembler::aboveEqual, *overflow); __ bind(done); } diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index f3390c94ca9..6318a958517 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -299,7 +299,6 @@ void InterpreterGenerator::generate_counter_incr( // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not. if (TieredCompilation) { int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { // Are we profiling? @@ -309,6 +308,7 @@ void InterpreterGenerator::generate_counter_incr( // Increment counter in the MDO const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rax, in_bytes(MethodData::invoke_mask_offset())); __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ jmp(done); } @@ -318,10 +318,11 @@ void InterpreterGenerator::generate_counter_incr( MethodCounters::invocation_counter_offset() + InvocationCounter::counter_offset()); __ get_method_counters(rbx, rax, done); + const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset())); __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ bind(done); - } else { + } else { // not TieredCompilation const Address backedge_counter(rax, MethodCounters::backedge_counter_offset() + InvocationCounter::counter_offset()); @@ -350,14 +351,16 @@ void InterpreterGenerator::generate_counter_incr( if (ProfileInterpreter && profile_method != NULL) { // Test to see if we should create a method data oop - __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, *profile_method_continue); // if no method data exists, go to profile_method __ test_method_data_pointer(rax, *profile_method); } - __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_invocation_limit_offset()))); __ jcc(Assembler::aboveEqual, *overflow); __ bind(done); } diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp index 2187056a384..d0bdc33905c 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp @@ -1621,7 +1621,6 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (TieredCompilation) { Label no_mdo; int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { // Are we profiling? __ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset()))); @@ -1630,6 +1629,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Increment the MDO backedge counter const Address mdo_backedge_counter(rbx, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rbx, in_bytes(MethodData::backedge_mask_offset())); __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); __ jmp(dispatch); @@ -1637,9 +1637,10 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ bind(no_mdo); // Increment backedge counter in MethodCounters* __ movptr(rcx, Address(rcx, Method::method_counters_offset())); + const Address mask(rcx, in_bytes(MethodCounters::backedge_mask_offset())); __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); - } else { + } else { // not TieredCompilation // increment counter __ movptr(rcx, Address(rcx, Method::method_counters_offset())); __ movl(rax, Address(rcx, be_offset)); // load backedge counter @@ -1653,8 +1654,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (ProfileInterpreter) { // Test to see if we should create a method data oop - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, dispatch); // if no method data exists, go to profile method @@ -1662,8 +1662,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (UseOnStackReplacement) { // check for overflow against rbx, which is the MDO taken count - __ cmp32(rbx, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rbx, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::below, dispatch); // When ProfileInterpreter is on, the backedge_count comes from the @@ -1678,8 +1677,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { } else { if (UseOnStackReplacement) { // check for overflow against rax, which is the sum of the counters - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::aboveEqual, backedge_counter_overflow); } diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp index b1b1b00a615..82072f0c920 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp @@ -1642,7 +1642,6 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (TieredCompilation) { Label no_mdo; int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { // Are we profiling? __ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset()))); @@ -1651,6 +1650,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Increment the MDO backedge counter const Address mdo_backedge_counter(rbx, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rbx, in_bytes(MethodData::backedge_mask_offset())); __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); __ jmp(dispatch); @@ -1658,9 +1658,10 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ bind(no_mdo); // Increment backedge counter in MethodCounters* __ movptr(rcx, Address(rcx, Method::method_counters_offset())); + const Address mask(rcx, in_bytes(MethodCounters::backedge_mask_offset())); __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); - } else { + } else { // not TieredCompilation // increment counter __ movptr(rcx, Address(rcx, Method::method_counters_offset())); __ movl(rax, Address(rcx, be_offset)); // load backedge counter @@ -1674,8 +1675,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (ProfileInterpreter) { // Test to see if we should create a method data oop - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, dispatch); // if no method data exists, go to profile method @@ -1683,8 +1683,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (UseOnStackReplacement) { // check for overflow against ebx which is the MDO taken count - __ cmp32(rbx, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rbx, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::below, dispatch); // When ProfileInterpreter is on, the backedge_count comes @@ -1702,8 +1701,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (UseOnStackReplacement) { // check for overflow against eax, which is the sum of the // counters - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::aboveEqual, backedge_counter_overflow); } diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 2beb72a60f1..8fe99af08ad 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -32,6 +32,7 @@ #include "ci/ciArrayKlass.hpp" #include "ci/ciInstance.hpp" #include "ci/ciObjArray.hpp" +#include "runtime/arguments.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/vm_version.hpp" @@ -3351,7 +3352,12 @@ void LIRGenerator::do_ProfileInvoke(ProfileInvoke* x) { if (!x->inlinee()->is_accessor()) { CodeEmitInfo* info = state_for(x, x->state(), true); // Notify the runtime very infrequently only to take care of counter overflows - increment_event_counter_impl(info, x->inlinee(), (1 << Tier23InlineeNotifyFreqLog) - 1, InvocationEntryBci, false, true); + int freq_log = Tier23InlineeNotifyFreqLog; + double scale; + if (_method->has_option_value("CompileThresholdScaling", scale)) { + freq_log = Arguments::scaled_freq_log(freq_log, scale); + } + increment_event_counter_impl(info, x->inlinee(), right_n_bits(freq_log), InvocationEntryBci, false, true); } } @@ -3366,7 +3372,11 @@ void LIRGenerator::increment_event_counter(CodeEmitInfo* info, int bci, bool bac ShouldNotReachHere(); } // Increment the appropriate invocation/backedge counter and notify the runtime. - increment_event_counter_impl(info, info->scope()->method(), (1 << freq_log) - 1, bci, backedge, true); + double scale; + if (_method->has_option_value("CompileThresholdScaling", scale)) { + freq_log = Arguments::scaled_freq_log(freq_log, scale); + } + increment_event_counter_impl(info, info->scope()->method(), right_n_bits(freq_log), bci, backedge, true); } void LIRGenerator::decrement_age(CodeEmitInfo* info) { diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 4f0def89a20..71b3fc5b3bf 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -1470,7 +1470,9 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci, // The method may be explicitly excluded by the user. bool quietly; - if (CompilerOracle::should_exclude(method, quietly)) { + double scale; + if (CompilerOracle::should_exclude(method, quietly) + || (CompilerOracle::has_option_value(method, "CompileThresholdScaling", scale) && scale == 0)) { if (!quietly) { // This does not happen quietly... ResourceMark rm; diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index 2bf9a20f27d..5ec7ec89dbe 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -53,7 +53,7 @@ /* * USELABELS - If using GCC, then use labels for the opcode dispatching * rather -then a switch statement. This improves performance because it - * gives us the oportunity to have the instructions that calculate the + * gives us the opportunity to have the instructions that calculate the * next opcode to jump to be intermixed with the rest of the instructions * that implement the opcode (see UPDATE_PC_AND_TOS_AND_CONTINUE macro). */ diff --git a/hotspot/src/share/vm/interpreter/invocationCounter.hpp b/hotspot/src/share/vm/interpreter/invocationCounter.hpp index e0cb50cbe09..0409b02f693 100644 --- a/hotspot/src/share/vm/interpreter/invocationCounter.hpp +++ b/hotspot/src/share/vm/interpreter/invocationCounter.hpp @@ -36,7 +36,7 @@ // Implementation notes: For space reasons, state & counter are both encoded in one word, // The state is encoded using some of the least significant bits, the counter is using the // more significant bits. The counter is incremented before a method is activated and an -// action is triggered when when count() > limit(). +// action is triggered when count() > limit(). class InvocationCounter VALUE_OBJ_CLASS_SPEC { friend class VMStructs; @@ -48,7 +48,6 @@ class InvocationCounter VALUE_OBJ_CLASS_SPEC { number_of_state_bits = 2, number_of_carry_bits = 1, number_of_noncount_bits = number_of_state_bits + number_of_carry_bits, - number_of_count_bits = BitsPerInt - number_of_noncount_bits, state_limit = nth_bit(number_of_state_bits), count_grain = nth_bit(number_of_state_bits + number_of_carry_bits), carry_mask = right_n_bits(number_of_carry_bits) << number_of_state_bits, @@ -68,6 +67,7 @@ class InvocationCounter VALUE_OBJ_CLASS_SPEC { count_increment = count_grain, // use this value to increment the 32bit _counter word count_mask_value = count_mask, // use this value to mask the backedge counter count_shift = number_of_noncount_bits, + number_of_count_bits = BitsPerInt - number_of_noncount_bits, count_limit = nth_bit(number_of_count_bits - 1) }; diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 62a1501ab95..9e37b0b8504 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -412,15 +412,14 @@ MethodCounters* Method::build_method_counters(Method* m, TRAPS) { } methodHandle mh(m); - ClassLoaderData* loader_data = mh->method_holder()->class_loader_data(); - MethodCounters* counters = MethodCounters::allocate(loader_data, THREAD); + MethodCounters* counters = MethodCounters::allocate(mh, THREAD); if (HAS_PENDING_EXCEPTION) { CompileBroker::log_metaspace_failure(); ClassLoaderDataGraph::set_metaspace_oom(true); return NULL; // return the exception (which is cleared) } if (!mh->init_method_counters(counters)) { - MetadataFactory::free_metadata(loader_data, counters); + MetadataFactory::free_metadata(mh->method_holder()->class_loader_data(), counters); } return mh->method_counters(); } diff --git a/hotspot/src/share/vm/oops/methodCounters.cpp b/hotspot/src/share/vm/oops/methodCounters.cpp index 25379d25658..b78b6e8046b 100644 --- a/hotspot/src/share/vm/oops/methodCounters.cpp +++ b/hotspot/src/share/vm/oops/methodCounters.cpp @@ -23,10 +23,11 @@ */ #include "precompiled.hpp" #include "oops/methodCounters.hpp" -#include "runtime/thread.inline.hpp" +#include "runtime/handles.inline.hpp" -MethodCounters* MethodCounters::allocate(ClassLoaderData* loader_data, TRAPS) { - return new(loader_data, size(), false, MetaspaceObj::MethodCountersType, THREAD) MethodCounters(); +MethodCounters* MethodCounters::allocate(methodHandle mh, TRAPS) { + ClassLoaderData* loader_data = mh->method_holder()->class_loader_data(); + return new(loader_data, size(), false, MetaspaceObj::MethodCountersType, THREAD) MethodCounters(mh); } void MethodCounters::clear_counters() { diff --git a/hotspot/src/share/vm/oops/methodCounters.hpp b/hotspot/src/share/vm/oops/methodCounters.hpp index a21d376b871..7d042bf72a1 100644 --- a/hotspot/src/share/vm/oops/methodCounters.hpp +++ b/hotspot/src/share/vm/oops/methodCounters.hpp @@ -26,7 +26,9 @@ #define SHARE_VM_OOPS_METHODCOUNTERS_HPP #include "oops/metadata.hpp" +#include "compiler/compilerOracle.hpp" #include "interpreter/invocationCounter.hpp" +#include "runtime/arguments.hpp" class MethodCounters: public MetaspaceObj { friend class VMStructs; @@ -45,7 +47,11 @@ class MethodCounters: public MetaspaceObj { // 3. (INT_MIN..0] - method is hot and will deopt and get // recompiled without the counters int _nmethod_age; - + int _interpreter_invocation_limit; // per-method InterpreterInvocationLimit + int _interpreter_backward_branch_limit; // per-method InterpreterBackwardBranchLimit + int _interpreter_profile_limit; // per-method InterpreterProfileLimit + int _invoke_mask; // per-method Tier0InvokeNotifyFreqLog + int _backedge_mask; // per-method Tier0BackedgeNotifyFreqLog #ifdef TIERED float _rate; // Events (invocation and backedge counter increments) per millisecond jlong _prev_time; // Previous time the rate was acquired @@ -53,15 +59,15 @@ class MethodCounters: public MetaspaceObj { u1 _highest_osr_comp_level; // Same for OSR level #endif - MethodCounters() : _interpreter_invocation_count(0), - _interpreter_throwout_count(0), - _number_of_breakpoints(0), - _nmethod_age(INT_MAX) + MethodCounters(methodHandle mh) : _interpreter_invocation_count(0), + _interpreter_throwout_count(0), + _number_of_breakpoints(0), + _nmethod_age(INT_MAX) #ifdef TIERED - , _rate(0), - _prev_time(0), - _highest_comp_level(0), - _highest_osr_comp_level(0) + , _rate(0), + _prev_time(0), + _highest_comp_level(0), + _highest_osr_comp_level(0) #endif { invocation_counter()->init(); @@ -70,10 +76,28 @@ class MethodCounters: public MetaspaceObj { if (StressCodeAging) { set_nmethod_age(HotMethodDetectionLimit); } + + // Set per-method thresholds. + double scale = 1.0; + CompilerOracle::has_option_value(mh, "CompileThresholdScaling", scale); + + int compile_threshold = Arguments::scaled_compile_threshold(CompileThreshold, scale); + _interpreter_invocation_limit = compile_threshold << InvocationCounter::count_shift; + if (ProfileInterpreter) { + // If interpreter profiling is enabled, the backward branch limit + // is compared against the method data counter rather than an invocation + // counter, therefore no shifting of bits is required. + _interpreter_backward_branch_limit = (compile_threshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100; + } else { + _interpreter_backward_branch_limit = ((compile_threshold * OnStackReplacePercentage) / 100) << InvocationCounter::count_shift; + } + _interpreter_profile_limit = ((compile_threshold * InterpreterProfilePercentage) / 100) << InvocationCounter::count_shift; + _invoke_mask = right_n_bits(Arguments::scaled_freq_log(Tier0InvokeNotifyFreqLog, scale)) << InvocationCounter::count_shift; + _backedge_mask = right_n_bits(Arguments::scaled_freq_log(Tier0BackedgeNotifyFreqLog, scale)) << InvocationCounter::count_shift; } public: - static MethodCounters* allocate(ClassLoaderData* loader_data, TRAPS); + static MethodCounters* allocate(methodHandle mh, TRAPS); void deallocate_contents(ClassLoaderData* loader_data) {} DEBUG_ONLY(bool on_stack() { return false; }) // for template @@ -161,5 +185,24 @@ class MethodCounters: public MetaspaceObj { return offset_of(MethodCounters, _interpreter_invocation_count); } + static ByteSize interpreter_invocation_limit_offset() { + return byte_offset_of(MethodCounters, _interpreter_invocation_limit); + } + + static ByteSize interpreter_backward_branch_limit_offset() { + return byte_offset_of(MethodCounters, _interpreter_backward_branch_limit); + } + + static ByteSize interpreter_profile_limit_offset() { + return byte_offset_of(MethodCounters, _interpreter_profile_limit); + } + + static ByteSize invoke_mask_offset() { + return byte_offset_of(MethodCounters, _invoke_mask); + } + + static ByteSize backedge_mask_offset() { + return byte_offset_of(MethodCounters, _backedge_mask); + } }; #endif //SHARE_VM_OOPS_METHODCOUNTERS_HPP diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index ef215581df1..f9e187f9add 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -31,6 +31,7 @@ #include "memory/heapInspection.hpp" #include "oops/methodData.hpp" #include "prims/jvmtiRedefineClasses.hpp" +#include "runtime/arguments.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" @@ -1131,6 +1132,13 @@ void MethodData::init() { _backedge_counter.init(); _invocation_counter_start = 0; _backedge_counter_start = 0; + + // Set per-method invoke- and backedge mask. + double scale = 1.0; + CompilerOracle::has_option_value(_method, "CompileThresholdScaling", scale); + _invoke_mask = right_n_bits(Arguments::scaled_freq_log(Tier0InvokeNotifyFreqLog, scale)) << InvocationCounter::count_shift; + _backedge_mask = right_n_bits(Arguments::scaled_freq_log(Tier0BackedgeNotifyFreqLog, scale)) << InvocationCounter::count_shift; + _tenure_traps = 0; _num_loops = 0; _num_blocks = 0; diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index e91cffb8375..d06974672ee 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -2088,6 +2088,8 @@ private: int _invocation_counter_start; int _backedge_counter_start; uint _tenure_traps; + int _invoke_mask; // per-method Tier0InvokeNotifyFreqLog + int _backedge_mask; // per-method Tier0BackedgeNotifyFreqLog #if INCLUDE_RTM_OPT // State of RTM code generation during compilation of the method @@ -2447,10 +2449,19 @@ public: static ByteSize invocation_counter_offset() { return byte_offset_of(MethodData, _invocation_counter); } + static ByteSize backedge_counter_offset() { return byte_offset_of(MethodData, _backedge_counter); } + static ByteSize invoke_mask_offset() { + return byte_offset_of(MethodData, _invoke_mask); + } + + static ByteSize backedge_mask_offset() { + return byte_offset_of(MethodData, _backedge_mask); + } + static ByteSize parameters_type_data_di_offset() { return byte_offset_of(MethodData, _parameters_type_data_di); } diff --git a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp index bd78c3dec77..eb83161ca43 100644 --- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp +++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp @@ -155,7 +155,7 @@ bool AdvancedThresholdPolicy::is_method_profiled(Method* method) { if (mdo != NULL) { int i = mdo->invocation_count_delta(); int b = mdo->backedge_count_delta(); - return call_predicate_helper(i, b, 1); + return call_predicate_helper(i, b, 1, method); } return false; } @@ -229,32 +229,32 @@ double AdvancedThresholdPolicy::threshold_scale(CompLevel level, int feedback_k) // Tier?LoadFeedback is basically a coefficient that determines of // how many methods per compiler thread can be in the queue before // the threshold values double. -bool AdvancedThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level) { +bool AdvancedThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level, Method* method) { switch(cur_level) { case CompLevel_none: case CompLevel_limited_profile: { double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); - return loop_predicate_helper(i, b, k); + return loop_predicate_helper(i, b, k, method); } case CompLevel_full_profile: { double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback); - return loop_predicate_helper(i, b, k); + return loop_predicate_helper(i, b, k, method); } default: return true; } } -bool AdvancedThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level) { +bool AdvancedThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level, Method* method) { switch(cur_level) { case CompLevel_none: case CompLevel_limited_profile: { double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); - return call_predicate_helper(i, b, k); + return call_predicate_helper(i, b, k, method); } case CompLevel_full_profile: { double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback); - return call_predicate_helper(i, b, k); + return call_predicate_helper(i, b, k, method); } default: return true; @@ -271,7 +271,7 @@ bool AdvancedThresholdPolicy::should_create_mdo(Method* method, CompLevel cur_le int i = method->invocation_count(); int b = method->backedge_count(); double k = Tier0ProfilingStartPercentage / 100.0; - return call_predicate_helper(i, b, k) || loop_predicate_helper(i, b, k); + return call_predicate_helper(i, b, k, method) || loop_predicate_helper(i, b, k, method); } return false; } @@ -348,7 +348,7 @@ CompLevel AdvancedThresholdPolicy::common(Predicate p, Method* method, CompLevel // If we were at full profile level, would we switch to full opt? if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) { next_level = CompLevel_full_optimization; - } else if ((this->*p)(i, b, cur_level)) { + } else if ((this->*p)(i, b, cur_level, method)) { // C1-generated fully profiled code is about 30% slower than the limited profile // code that has only invocation and backedge counters. The observation is that // if C2 queue is large enough we can spend too much time in the fully profiled code @@ -374,7 +374,7 @@ CompLevel AdvancedThresholdPolicy::common(Predicate p, Method* method, CompLevel if (mdo->would_profile()) { if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= Tier3DelayOff * compiler_count(CompLevel_full_optimization) && - (this->*p)(i, b, cur_level))) { + (this->*p)(i, b, cur_level, method))) { next_level = CompLevel_full_profile; } } else { @@ -390,7 +390,7 @@ CompLevel AdvancedThresholdPolicy::common(Predicate p, Method* method, CompLevel if (mdo->would_profile()) { int mdo_i = mdo->invocation_count_delta(); int mdo_b = mdo->backedge_count_delta(); - if ((this->*p)(mdo_i, mdo_b, cur_level)) { + if ((this->*p)(mdo_i, mdo_b, cur_level, method)) { next_level = CompLevel_full_optimization; } } else { diff --git a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp index a22451102c2..5ec406388f3 100644 --- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp +++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp @@ -84,7 +84,7 @@ class CompileQueue; * invocation and backedge notifications. Basically every n-th invocation or backedge a mutator thread * makes a call into the runtime. * - * - Tier?CompileThreshold, Tier?BackEdgeThreshold, Tier?MinInvocationThreshold control + * - Tier?InvocationThreshold, Tier?CompileThreshold, Tier?BackEdgeThreshold, Tier?MinInvocationThreshold control * compilation thresholds. * Level 2 thresholds are not used and are provided for option-compatibility and potential future use. * Other thresholds work as follows: @@ -100,7 +100,9 @@ class CompileQueue; * The same predicate is used to control the transition from level 3 to level 4 (C2). It should be * noted though that the thresholds are relative. Moreover i and b for the 0->3 transition come * from Method* and for 3->4 transition they come from MDO (since profiled invocations are - * counted separately). + * counted separately). Finally, if a method does not contain anything worth profiling, a transition + * from level 3 to level 4 occurs without considering thresholds (e.g., with fewer invocations than + * what is specified by Tier4InvocationThreshold). * * OSR transitions are controlled simply with b > TierXBackEdgeThreshold * s predicates. * @@ -164,9 +166,9 @@ class AdvancedThresholdPolicy : public SimpleThresholdPolicy { // Call and loop predicates determine whether a transition to a higher compilation // level should be performed (pointers to predicate functions are passed to common(). // Predicates also take compiler load into account. - typedef bool (AdvancedThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level); - bool call_predicate(int i, int b, CompLevel cur_level); - bool loop_predicate(int i, int b, CompLevel cur_level); + typedef bool (AdvancedThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level, Method* method); + bool call_predicate(int i, int b, CompLevel cur_level, Method* method); + bool loop_predicate(int i, int b, CompLevel cur_level, Method* method); // Common transition function. Given a predicate determines if a method should transition to another level. CompLevel common(Predicate p, Method* method, CompLevel cur_level, bool disable_feedback = false); // Transition functions. diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 66500908d85..0c31c9bc112 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1126,16 +1126,35 @@ static void no_shared_spaces(const char* message) { } #endif -// Returns threshold scaled with CompileThresholdScaling -intx Arguments::get_scaled_compile_threshold(intx threshold) { - return (intx)(threshold * CompileThresholdScaling); +intx Arguments::scaled_compile_threshold(intx threshold, double scale) { + if (scale == 1.0 || scale < 0.0) { + return threshold; + } else { + return (intx)(threshold * scale); + } } // Returns freq_log scaled with CompileThresholdScaling -intx Arguments::get_scaled_freq_log(intx freq_log) { - intx scaled_freq = get_scaled_compile_threshold((intx)1 << freq_log); - if (scaled_freq == 0) { - return 0; +intx Arguments::scaled_freq_log(intx freq_log, double scale) { + // Check if scaling is necessary or negative value was specified. + if (scale == 1.0 || scale < 0.0) { + return freq_log; + } + + // Check value to avoid calculating log2 of 0. + if (scale == 0.0) { + return 1; + } + + intx scaled_freq = scaled_compile_threshold((intx)1 << freq_log, scale); + // Determine the maximum notification frequency value currently supported. + // The largest mask value that the interpreter/C1 can handle is + // of length InvocationCounter::number_of_count_bits. Mask values are always + // one bit shorter then the value of the notification frequency. Set + // max_freq_bits accordingly. + intx max_freq_bits = InvocationCounter::number_of_count_bits + 1; + if (scaled_freq > nth_bit(max_freq_bits)) { + return max_freq_bits; } else { return log2_intptr(scaled_freq); } @@ -1180,31 +1199,36 @@ void Arguments::set_tiered_flags() { Tier3InvokeNotifyFreqLog = 0; Tier4InvocationThreshold = 0; } + + if (CompileThresholdScaling < 0) { + vm_exit_during_initialization("Negative value specified for CompileThresholdScaling", NULL); + } + // Scale tiered compilation thresholds if (!FLAG_IS_DEFAULT(CompileThresholdScaling)) { - FLAG_SET_ERGO(intx, Tier0InvokeNotifyFreqLog, get_scaled_freq_log(Tier0InvokeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier0BackedgeNotifyFreqLog, get_scaled_freq_log(Tier0BackedgeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier0InvokeNotifyFreqLog, scaled_freq_log(Tier0InvokeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier0BackedgeNotifyFreqLog, scaled_freq_log(Tier0BackedgeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier3InvocationThreshold, get_scaled_compile_threshold(Tier3InvocationThreshold)); - FLAG_SET_ERGO(intx, Tier3MinInvocationThreshold, get_scaled_compile_threshold(Tier3MinInvocationThreshold)); - FLAG_SET_ERGO(intx, Tier3CompileThreshold, get_scaled_compile_threshold(Tier3CompileThreshold)); - FLAG_SET_ERGO(intx, Tier3BackEdgeThreshold, get_scaled_compile_threshold(Tier3BackEdgeThreshold)); + FLAG_SET_ERGO(intx, Tier3InvocationThreshold, scaled_compile_threshold(Tier3InvocationThreshold)); + FLAG_SET_ERGO(intx, Tier3MinInvocationThreshold, scaled_compile_threshold(Tier3MinInvocationThreshold)); + FLAG_SET_ERGO(intx, Tier3CompileThreshold, scaled_compile_threshold(Tier3CompileThreshold)); + FLAG_SET_ERGO(intx, Tier3BackEdgeThreshold, scaled_compile_threshold(Tier3BackEdgeThreshold)); // Tier2{Invocation,MinInvocation,Compile,Backedge}Threshold should be scaled here // once these thresholds become supported. - FLAG_SET_ERGO(intx, Tier2InvokeNotifyFreqLog, get_scaled_freq_log(Tier2InvokeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier2BackedgeNotifyFreqLog, get_scaled_freq_log(Tier2BackedgeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier2InvokeNotifyFreqLog, scaled_freq_log(Tier2InvokeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier2BackedgeNotifyFreqLog, scaled_freq_log(Tier2BackedgeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier3InvokeNotifyFreqLog, get_scaled_freq_log(Tier3InvokeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier3BackedgeNotifyFreqLog, get_scaled_freq_log(Tier3BackedgeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier3InvokeNotifyFreqLog, scaled_freq_log(Tier3InvokeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier3BackedgeNotifyFreqLog, scaled_freq_log(Tier3BackedgeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier23InlineeNotifyFreqLog, get_scaled_freq_log(Tier23InlineeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier23InlineeNotifyFreqLog, scaled_freq_log(Tier23InlineeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier4InvocationThreshold, get_scaled_compile_threshold(Tier4InvocationThreshold)); - FLAG_SET_ERGO(intx, Tier4MinInvocationThreshold, get_scaled_compile_threshold(Tier4MinInvocationThreshold)); - FLAG_SET_ERGO(intx, Tier4CompileThreshold, get_scaled_compile_threshold(Tier4CompileThreshold)); - FLAG_SET_ERGO(intx, Tier4BackEdgeThreshold, get_scaled_compile_threshold(Tier4BackEdgeThreshold)); + FLAG_SET_ERGO(intx, Tier4InvocationThreshold, scaled_compile_threshold(Tier4InvocationThreshold)); + FLAG_SET_ERGO(intx, Tier4MinInvocationThreshold, scaled_compile_threshold(Tier4MinInvocationThreshold)); + FLAG_SET_ERGO(intx, Tier4CompileThreshold, scaled_compile_threshold(Tier4CompileThreshold)); + FLAG_SET_ERGO(intx, Tier4BackEdgeThreshold, scaled_compile_threshold(Tier4BackEdgeThreshold)); } } @@ -3456,7 +3480,7 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req } if ((TieredCompilation && CompileThresholdScaling == 0) - || (!TieredCompilation && get_scaled_compile_threshold(CompileThreshold) == 0)) { + || (!TieredCompilation && scaled_compile_threshold(CompileThreshold) == 0)) { set_mode_flags(_int); } @@ -3896,7 +3920,7 @@ jint Arguments::apply_ergo() { } // Scale CompileThreshold if (!FLAG_IS_DEFAULT(CompileThresholdScaling)) { - FLAG_SET_ERGO(intx, CompileThreshold, get_scaled_compile_threshold(CompileThreshold)); + FLAG_SET_ERGO(intx, CompileThreshold, scaled_compile_threshold(CompileThreshold)); } } diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index a0edd81f2e6..ae726b82fdc 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -328,9 +328,6 @@ class Arguments : AllStatic { static bool _ClipInlining; static bool _CIDynamicCompilePriority; - // Scale compile thresholds - static intx get_scaled_compile_threshold(intx threshold); - static intx get_scaled_freq_log(intx freq_log); // Tiered static void set_tiered_flags(); static int get_min_number_of_compiler_threads(); @@ -452,6 +449,18 @@ class Arguments : AllStatic { static char* SharedArchivePath; public: + // Scale compile thresholds + // Returns threshold scaled with CompileThresholdScaling + static intx scaled_compile_threshold(intx threshold, double scale); + static intx scaled_compile_threshold(intx threshold) { + return scaled_compile_threshold(threshold, CompileThresholdScaling); + } + // Returns freq_log scaled with CompileThresholdScaling + static intx scaled_freq_log(intx freq_log, double scale); + static intx scaled_freq_log(intx freq_log) { + return scaled_freq_log(freq_log, CompileThresholdScaling); + } + // Parses the arguments, first phase static jint parse(const JavaVMInitArgs* args); // Apply ergonomics diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 6d56c2f93d6..dd014368f69 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -2477,7 +2477,7 @@ class CommandLineFlags { "Number of compiler threads to run") \ \ product(intx, CompilationPolicyChoice, 0, \ - "which compilation policy (0/1)") \ + "which compilation policy (0-3)") \ \ develop(bool, UseStackBanging, true, \ "use stack banging for stack overflow checks (required for " \ @@ -3528,7 +3528,16 @@ class CommandLineFlags { \ product(double, CompileThresholdScaling, 1.0, \ "Factor to control when first compilation happens " \ - "(both with and without tiered compilation)") \ + "(both with and without tiered compilation): " \ + "values greater than 1.0 delay counter overflow, " \ + "values between 0 and 1.0 rush counter overflow, " \ + "value of 1.0 leave compilation thresholds unchanged " \ + "value of 0.0 is equivalent to -Xint. " \ + "" \ + "Flag can be set as per-method option. " \ + "If a value is specified for a method, compilation thresholds " \ + "for that method are scaled by both the value of the global flag "\ + "and the value of the per-method flag.") \ \ product(intx, Tier0InvokeNotifyFreqLog, 7, \ "Interpreter (tier 0) invocation notification frequency") \ diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp index 11803f1f6a4..4b17ca2bc85 100644 --- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp @@ -257,28 +257,28 @@ void SimpleThresholdPolicy::submit_compile(methodHandle mh, int bci, CompLevel l // Call and loop predicates determine whether a transition to a higher // compilation level should be performed (pointers to predicate functions // are passed to common() transition function). -bool SimpleThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level) { +bool SimpleThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level, Method* method) { switch(cur_level) { case CompLevel_none: case CompLevel_limited_profile: { - return loop_predicate_helper(i, b, 1.0); + return loop_predicate_helper(i, b, 1.0, method); } case CompLevel_full_profile: { - return loop_predicate_helper(i, b, 1.0); + return loop_predicate_helper(i, b, 1.0, method); } default: return true; } } -bool SimpleThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level) { +bool SimpleThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level, Method* method) { switch(cur_level) { case CompLevel_none: case CompLevel_limited_profile: { - return call_predicate_helper(i, b, 1.0); + return call_predicate_helper(i, b, 1.0, method); } case CompLevel_full_profile: { - return call_predicate_helper(i, b, 1.0); + return call_predicate_helper(i, b, 1.0, method); } default: return true; @@ -293,8 +293,8 @@ bool SimpleThresholdPolicy::is_mature(Method* method) { int i = mdo->invocation_count(); int b = mdo->backedge_count(); double k = ProfileMaturityPercentage / 100.0; - return call_predicate_helper(i, b, k) || - loop_predicate_helper(i, b, k); + return call_predicate_helper(i, b, k, method) || + loop_predicate_helper(i, b, k, method); } return false; } @@ -313,7 +313,7 @@ CompLevel SimpleThresholdPolicy::common(Predicate p, Method* method, CompLevel c // If we were at full profile level, would we switch to full opt? if (common(p, method, CompLevel_full_profile) == CompLevel_full_optimization) { next_level = CompLevel_full_optimization; - } else if ((this->*p)(i, b, cur_level)) { + } else if ((this->*p)(i, b, cur_level, method)) { next_level = CompLevel_full_profile; } break; @@ -325,7 +325,7 @@ CompLevel SimpleThresholdPolicy::common(Predicate p, Method* method, CompLevel c if (mdo->would_profile()) { int mdo_i = mdo->invocation_count_delta(); int mdo_b = mdo->backedge_count_delta(); - if ((this->*p)(mdo_i, mdo_b, cur_level)) { + if ((this->*p)(mdo_i, mdo_b, cur_level, method)) { next_level = CompLevel_full_optimization; } } else { diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp index 49a9d893406..87d009e1360 100644 --- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp @@ -43,9 +43,9 @@ class SimpleThresholdPolicy : public CompilationPolicy { // Call and loop predicates determine whether a transition to a higher compilation // level should be performed (pointers to predicate functions are passed to common_TF(). // Predicates also take compiler load into account. - typedef bool (SimpleThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level); - bool call_predicate(int i, int b, CompLevel cur_level); - bool loop_predicate(int i, int b, CompLevel cur_level); + typedef bool (SimpleThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level, Method* method); + bool call_predicate(int i, int b, CompLevel cur_level, Method* method); + bool loop_predicate(int i, int b, CompLevel cur_level, Method* method); // Common transition function. Given a predicate determines if a method should transition to another level. CompLevel common(Predicate p, Method* method, CompLevel cur_level); // Transition functions. @@ -76,8 +76,8 @@ protected: // Predicate helpers are used by .*_predicate() methods as well as others. // They check the given counter values, multiplied by the scale against the thresholds. - template static inline bool call_predicate_helper(int i, int b, double scale); - template static inline bool loop_predicate_helper(int i, int b, double scale); + template static inline bool call_predicate_helper(int i, int b, double scale, Method* method); + template static inline bool loop_predicate_helper(int i, int b, double scale, Method* method); // Get a compilation level for a given method. static CompLevel comp_level(Method* method) { diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp index ff0a6cf8330..05b37c48084 100644 --- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp @@ -25,8 +25,14 @@ #ifndef SHARE_VM_RUNTIME_SIMPLETHRESHOLDPOLICY_INLINE_HPP #define SHARE_VM_RUNTIME_SIMPLETHRESHOLDPOLICY_INLINE_HPP +#include "compiler/compilerOracle.hpp" + template -bool SimpleThresholdPolicy::call_predicate_helper(int i, int b, double scale) { +bool SimpleThresholdPolicy::call_predicate_helper(int i, int b, double scale, Method* method) { + double threshold_scaling; + if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) { + scale *= threshold_scaling; + } switch(level) { case CompLevel_none: case CompLevel_limited_profile: @@ -40,7 +46,11 @@ bool SimpleThresholdPolicy::call_predicate_helper(int i, int b, double scale) { } template -bool SimpleThresholdPolicy::loop_predicate_helper(int i, int b, double scale) { +bool SimpleThresholdPolicy::loop_predicate_helper(int i, int b, double scale, Method* method) { + double threshold_scaling; + if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) { + scale *= threshold_scaling; + } switch(level) { case CompLevel_none: case CompLevel_limited_profile: diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 58b1a97a18e..d2dba088ea3 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -351,11 +351,18 @@ typedef TwoOopHashtable SymbolTwoOopHashtable; nonstatic_field(MethodData, _arg_stack, intx) \ nonstatic_field(MethodData, _arg_returned, intx) \ nonstatic_field(MethodData, _tenure_traps, uint) \ + nonstatic_field(MethodData, _invoke_mask, int) \ + nonstatic_field(MethodData, _backedge_mask, int) \ nonstatic_field(DataLayout, _header._struct._tag, u1) \ nonstatic_field(DataLayout, _header._struct._flags, u1) \ nonstatic_field(DataLayout, _header._struct._bci, u2) \ nonstatic_field(DataLayout, _cells[0], intptr_t) \ nonstatic_field(MethodCounters, _nmethod_age, int) \ + nonstatic_field(MethodCounters, _interpreter_invocation_limit, int) \ + nonstatic_field(MethodCounters, _interpreter_backward_branch_limit, int) \ + nonstatic_field(MethodCounters, _interpreter_profile_limit, int) \ + nonstatic_field(MethodCounters, _invoke_mask, int) \ + nonstatic_field(MethodCounters, _backedge_mask, int) \ nonstatic_field(MethodCounters, _interpreter_invocation_count, int) \ nonstatic_field(MethodCounters, _interpreter_throwout_count, u2) \ nonstatic_field(MethodCounters, _number_of_breakpoints, u2) \ diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 784db46775d..652da096e43 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -1142,17 +1142,18 @@ inline bool is_power_of_2_long(jlong x) { return ((x != NoLongBits) && (mask_long_bits(x, x - 1) == NoLongBits)); } -//* largest i such that 2^i <= x -// A negative value of 'x' will return '31' +// Returns largest i such that 2^i <= x. +// If x < 0, the function returns 31 on a 32-bit machine and 63 on a 64-bit machine. +// If x == 0, the function returns -1. inline int log2_intptr(intptr_t x) { int i = -1; - uintptr_t p = 1; + uintptr_t p = 1; while (p != 0 && p <= (uintptr_t)x) { // p = 2^(i+1) && p <= x (i.e., 2^(i+1) <= x) i++; p *= 2; } // p = 2^(i+1) && x < p (i.e., 2^i <= x < 2^(i+1)) - // (if p = 0 then overflow occurred and i = 31) + // If p = 0, overflow has occurred and i = 31 or i = 63 (depending on the machine word size). return i; } diff --git a/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java b/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java index b9837c2ba8d..5e611022762 100644 --- a/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java +++ b/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java @@ -54,7 +54,7 @@ public class CheckCompileThresholdScaling { // // Tier0InvokeNotifyFreqLog, Tier0BackedgeNotifyFreqLog, // Tier3InvocationThreshold, Tier3MinInvocationThreshold, - // Tier3CompileThreshold, and Tier3BackEdgeThreshold, + // Tier3CompileThreshold, Tier3BackEdgeThreshold, // Tier2InvokeNotifyFreqLog, Tier2BackedgeNotifyFreqLog, // Tier3InvokeNotifyFreqLog, Tier3BackedgeNotifyFreqLog, // Tier23InlineeNotifyFreqLog, Tier4InvocationThreshold, From 8e93b53e3e5994fb42f938a0f485eaec087c37c5 Mon Sep 17 00:00:00 2001 From: Katja Kantserova Date: Wed, 21 Jan 2015 15:06:31 +0100 Subject: [PATCH 30/72] 8069296: java/lang/management/MemoryMXBean/LowMemoryTest.java should be quarantined Reviewed-by: sla --- jdk/test/ProblemList.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index c6c35f2e4d6..4954f772f8a 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -123,7 +123,6 @@ # 8029891 java/lang/ClassLoader/deadlock/GetResource.java generic-all - ############################################################################ # jdk_instrument @@ -142,6 +141,9 @@ java/lang/instrument/RetransformBigClass.sh generic-all # 8058492 java/lang/management/ThreadMXBean/FindDeadlocks.java generic-all +# 8069286 +java/lang/management/MemoryMXBean/LowMemoryTest.java generic-all + ############################################################################ # jdk_jmx From 826e1b9739af72c8dd56ac3e4fe765cef596cd77 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 21 Jan 2015 19:36:18 +0100 Subject: [PATCH 31/72] 8069230: Remove unused G1PostBarrierStub::byte_map_base and friends Reviewed-by: brutisso, tschatzl --- hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp | 11 +---------- hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp | 11 +---------- hotspot/src/share/vm/c1/c1_CodeStubs.hpp | 11 +---------- 3 files changed, 3 insertions(+), 30 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp index f3709eb8d05..1187443000d 100644 --- a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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 @@ -483,15 +483,6 @@ void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { } -jbyte* G1PostBarrierStub::_byte_map_base = NULL; - -jbyte* G1PostBarrierStub::byte_map_base_slow() { - BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->is_a(BarrierSet::G1SATBCTLogging), - "Must be if we're using this."); - return ((G1SATBCardTableModRefBS*)bs)->byte_map_base; -} - void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); diff --git a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp index 718c82904f0..919c2a6df9c 100644 --- a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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 @@ -541,15 +541,6 @@ void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { } -jbyte* G1PostBarrierStub::_byte_map_base = NULL; - -jbyte* G1PostBarrierStub::byte_map_base_slow() { - BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->is_a(BarrierSet::G1SATBCTLogging), - "Must be if we're using this."); - return ((G1SATBCardTableModRefBS*)bs)->byte_map_base; -} - void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); assert(addr()->is_register(), "Precondition."); diff --git a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp index e3a4f4d5680..05a8c70506f 100644 --- a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp +++ b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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 @@ -601,15 +601,6 @@ class G1PostBarrierStub: public CodeStub { LIR_Opr _addr; LIR_Opr _new_val; - static jbyte* _byte_map_base; - static jbyte* byte_map_base_slow(); - static jbyte* byte_map_base() { - if (_byte_map_base == NULL) { - _byte_map_base = byte_map_base_slow(); - } - return _byte_map_base; - } - public: // addr (the address of the object head) and new_val must be registers. G1PostBarrierStub(LIR_Opr addr, LIR_Opr new_val): _addr(addr), _new_val(new_val) { } From 167de7ae02ce4e5338b8d1d5efc4c852ed7d61d6 Mon Sep 17 00:00:00 2001 From: Alexander Kulyakthin Date: Fri, 23 Jan 2015 14:20:52 +0100 Subject: [PATCH 32/72] 8067945: SVC jdk/test/* should be cleaned from JRE layout dependency Reviewed-by: sla --- jdk/test/com/sun/jdi/ImmutableResourceTest.sh | 2 +- jdk/test/com/sun/jdi/JITDebug.sh | 6 +++--- .../sun/jdi/connect/spi/JdiLoadedByCustomLoader.java | 11 +++-------- .../sun/jdi/connect/spi/JdiLoadedByCustomLoader.sh | 2 +- .../HotSpotDiagnosticMXBean/CheckOrigin.java | 6 +----- jdk/test/com/sun/tools/attach/BasicTests.java | 3 +-- jdk/test/com/sun/tools/attach/PermissionTest.java | 4 +--- jdk/test/com/sun/tools/attach/ProviderTest.java | 5 ++--- jdk/test/com/sun/tools/attach/TempDirTest.java | 4 +--- .../jmxremote/bootstrap/CustomLauncherTest.java | 8 +------- .../jmxremote/bootstrap/LocalManagementTest.java | 8 +------- 11 files changed, 16 insertions(+), 43 deletions(-) diff --git a/jdk/test/com/sun/jdi/ImmutableResourceTest.sh b/jdk/test/com/sun/jdi/ImmutableResourceTest.sh index 29c72ed6254..95bc8778b6e 100644 --- a/jdk/test/com/sun/jdi/ImmutableResourceTest.sh +++ b/jdk/test/com/sun/jdi/ImmutableResourceTest.sh @@ -92,7 +92,7 @@ fi # echo "JDK under test is: $TESTJAVA" # -CP="-classpath ${TESTCLASSES}${PATHSEP}${TESTJAVA}/lib/tools.jar" +CP="-classpath ${TESTCLASSES}" # Compile the test class using the classpath we need: # env diff --git a/jdk/test/com/sun/jdi/JITDebug.sh b/jdk/test/com/sun/jdi/JITDebug.sh index c647e1153b5..423fe26521a 100644 --- a/jdk/test/com/sun/jdi/JITDebug.sh +++ b/jdk/test/com/sun/jdi/JITDebug.sh @@ -103,15 +103,15 @@ if [ -z "${TESTJAVA}" ] ; then #if running standalone (no test harness of any kind), compile the #support files and the test case ${TESTJAVA}/bin/javac -d ${TESTCLASSES} \ - -classpath "$TESTJAVA/lib/tools.jar${PATHSEP}${TESTSRC}" \ + -classpath "${TESTSRC}" \ TestScaffold.java VMConnection.java TargetListener.java TargetAdapter.java ${TESTJAVA}/bin/javac -d ${TESTCLASSES} \ - -classpath "$TESTJAVA/lib/tools.jar${PATHSEP}${TESTSRC}" -g \ + -classpath "${TESTSRC}" -g \ JITDebug.java fi echo "JDK under test is: $TESTJAVA" # -CLASSPATH="$TESTJAVA/lib/tools.jar${PATHSEP}${TESTCLASSES}" +CLASSPATH="${TESTCLASSES}" export CLASSPATH CP="-classpath \"${CLASSPATH}\"" # diff --git a/jdk/test/com/sun/jdi/connect/spi/JdiLoadedByCustomLoader.java b/jdk/test/com/sun/jdi/connect/spi/JdiLoadedByCustomLoader.java index c01f54a79f4..11a522c727f 100644 --- a/jdk/test/com/sun/jdi/connect/spi/JdiLoadedByCustomLoader.java +++ b/jdk/test/com/sun/jdi/connect/spi/JdiLoadedByCustomLoader.java @@ -22,9 +22,8 @@ */ /* - * Creates a URLClassLoader from 2 file URLs. The first - * file URL is constructed from the given argument. The - * second is the SDK tools.jar. Once created the test + * Creates a URLClassLoader from a file URL. The file URL + * is constructed from the given argument. Once created the test * attempts to load another test case (ListConnectors) * using the class loader and then it invokes the list() * method. @@ -39,13 +38,9 @@ public class JdiLoadedByCustomLoader { public static void main(String args[]) throws Exception { // create files from given arguments and tools.jar File f1 = new File(args[0]); - String home = System.getProperty("java.home"); - String tools = ".." + File.separatorChar + "lib" + - File.separatorChar + "tools.jar"; - File f2 = (new File(home, tools)).getCanonicalFile(); // create class loader - URL[] urls = { f1.toURL(), f2.toURL() }; + URL[] urls = { f1.toURL() }; URLClassLoader cl = new URLClassLoader(urls); // load ListConnectors using the class loader diff --git a/jdk/test/com/sun/jdi/connect/spi/JdiLoadedByCustomLoader.sh b/jdk/test/com/sun/jdi/connect/spi/JdiLoadedByCustomLoader.sh index 2b104822b17..d508c00c727 100644 --- a/jdk/test/com/sun/jdi/connect/spi/JdiLoadedByCustomLoader.sh +++ b/jdk/test/com/sun/jdi/connect/spi/JdiLoadedByCustomLoader.sh @@ -68,7 +68,7 @@ SOMEOTHERDIR="${TESTCLASSES}"/someotherdir $JAVAC -d "${TESTCLASSES}" "${TESTSRC}"/JdiLoadedByCustomLoader.java mkdir "${SOMEOTHERDIR}" -$JAVAC -d "${SOMEOTHERDIR}" -classpath "${TESTSRC}${PS}${TESTJAVA}/lib/tools.jar" \ +$JAVAC -d "${SOMEOTHERDIR}" -classpath "${TESTSRC}" \ "${TESTSRC}"/ListConnectors.java # Run the test diff --git a/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/CheckOrigin.java b/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/CheckOrigin.java index 378310cf56a..27d80ffa106 100644 --- a/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/CheckOrigin.java +++ b/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/CheckOrigin.java @@ -62,7 +62,7 @@ public class CheckOrigin { "-XX:+UseConcMarkSweepGC", // this will cause UseParNewGC to be FLAG_SET_ERGO "-XX:+PrintGCDetails", "-XX:Flags=" + flagsFile.getAbsolutePath(), - "-cp", System.getProperty("test.class.path") + File.pathSeparator + getToolsJarPath(), + "-cp", System.getProperty("test.class.path"), "CheckOrigin", "-runtests"); @@ -137,8 +137,4 @@ public class CheckOrigin { vm.detach(); } - private static String getToolsJarPath() { - return System.getProperty("java.home") + - "/../lib/tools.jar".replace("/", File.separator); - } } diff --git a/jdk/test/com/sun/tools/attach/BasicTests.java b/jdk/test/com/sun/tools/attach/BasicTests.java index e462cf6463f..e5f4b4bd941 100644 --- a/jdk/test/com/sun/tools/attach/BasicTests.java +++ b/jdk/test/com/sun/tools/attach/BasicTests.java @@ -80,8 +80,7 @@ public class BasicTests { // Need to add jdk/lib/tools.jar to classpath. String classpath = - System.getProperty("test.class.path", "") + File.pathSeparator + - System.getProperty("test.jdk", ".") + sep + "lib" + sep + "tools.jar"; + System.getProperty("test.class.path", ""); String testClassDir = System.getProperty("test.classes", "") + sep; // Argumenta : -classpath cp BasicTests$TestMain pid agent badagent redefineagent diff --git a/jdk/test/com/sun/tools/attach/PermissionTest.java b/jdk/test/com/sun/tools/attach/PermissionTest.java index 471f6fc5953..b171fcea593 100644 --- a/jdk/test/com/sun/tools/attach/PermissionTest.java +++ b/jdk/test/com/sun/tools/attach/PermissionTest.java @@ -71,10 +71,8 @@ public class PermissionTest { private static void runTests(long pid) throws Throwable { final String sep = File.separator; - // Need to add jdk/lib/tools.jar to classpath. String classpath = - System.getProperty("test.class.path", "") + File.pathSeparator + - System.getProperty("test.jdk", ".") + sep + "lib" + sep + "tools.jar"; + System.getProperty("test.class.path", ""); String testSrc = System.getProperty("test.src", "") + sep; // Use a policy that will NOT allow attach. Test will verify exception. diff --git a/jdk/test/com/sun/tools/attach/ProviderTest.java b/jdk/test/com/sun/tools/attach/ProviderTest.java index 883951f444d..146c17f071b 100644 --- a/jdk/test/com/sun/tools/attach/ProviderTest.java +++ b/jdk/test/com/sun/tools/attach/ProviderTest.java @@ -68,11 +68,10 @@ public class ProviderTest { String testClasses = System.getProperty("test.classes", "") + sep; String jdkLib = System.getProperty("test.jdk", ".") + sep + "lib" + sep; - // Need to add SimpleProvider.jar and tools.jar to classpath. + // Need to add SimpleProvider.jar to classpath. String classpath = testClassPath + File.pathSeparator + - testClasses + "SimpleProvider.jar" + File.pathSeparator + - jdkLib + "tools.jar"; + testClasses + "SimpleProvider.jar"; String[] args = { "-classpath", diff --git a/jdk/test/com/sun/tools/attach/TempDirTest.java b/jdk/test/com/sun/tools/attach/TempDirTest.java index 86e3edda742..7aa41dc80d6 100644 --- a/jdk/test/com/sun/tools/attach/TempDirTest.java +++ b/jdk/test/com/sun/tools/attach/TempDirTest.java @@ -120,10 +120,8 @@ public class TempDirTest { private static void launchTests(long pid, Path clientTmpDir) throws Throwable { final String sep = File.separator; - // Need to add jdk/lib/tools.jar to classpath. String classpath = - System.getProperty("test.class.path", "") + File.pathSeparator + - System.getProperty("test.jdk", ".") + sep + "lib" + sep + "tools.jar"; + System.getProperty("test.class.path", ""); String[] tmpDirArg = null; if (clientTmpDir != null) { diff --git a/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java b/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java index ac0911a52ca..0f2978f9b71 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java +++ b/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java @@ -145,13 +145,7 @@ public class CustomLauncherTest { ProcessBuilder client = ProcessTools.createJavaProcessBuilder( "-cp", - TEST_CLASSPATH + - File.pathSeparator + - TEST_JDK + - File.separator + - "lib" + - File.separator + - "tools.jar", + TEST_CLASSPATH, "TestManager", String.valueOf(serverPrc.getPid()), port.get(), diff --git a/jdk/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java b/jdk/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java index 87ab6a9245e..1306f4e31a6 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java +++ b/jdk/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java @@ -132,13 +132,7 @@ public class LocalManagementTest { ProcessBuilder client = ProcessTools.createJavaProcessBuilder( "-cp", - TEST_CLASSPATH + - File.pathSeparator + - TEST_JDK + - File.separator + - "lib" + - File.separator + - "tools.jar", + TEST_CLASSPATH, "TestManager", String.valueOf(serverPrc.getPid()), port.get(), From 04474d85c1337e364edc909747eaa80ce6803248 Mon Sep 17 00:00:00 2001 From: Mattias Tobiasson Date: Mon, 26 Jan 2015 08:52:46 +0100 Subject: [PATCH 33/72] 8044419: TEST_BUG: com/sun/jdi/JdbReadTwiceTest.sh fails when run under root Reviewed-by: dsamersoff, sla --- jdk/test/ProblemList.txt | 3 -- jdk/test/com/sun/jdi/JdbReadTwiceTest.sh | 48 ++++++++++++++---------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 4954f772f8a..cbe3f74a044 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -292,9 +292,6 @@ com/sun/jdi/JdbMethodExitTest.sh generic-all # 8043571 com/sun/jdi/RepStep.java generic-all -# 8044419 -com/sun/jdi/JdbReadTwiceTest.sh generic-all - # 8058616 com/sun/jdi/RedefinePop.sh generic-all diff --git a/jdk/test/com/sun/jdi/JdbReadTwiceTest.sh b/jdk/test/com/sun/jdi/JdbReadTwiceTest.sh index b7ca50de096..0c78fe5ec81 100644 --- a/jdk/test/com/sun/jdi/JdbReadTwiceTest.sh +++ b/jdk/test/com/sun/jdi/JdbReadTwiceTest.sh @@ -204,27 +204,37 @@ if [ ! -r c:/ ] ; then clean fi +echo +echo "+++++++++++++++++++++++++++++++++++" +echo "Read an unreadable file - verify the read fails." -if [ ! -r c:/ ] ; then - # Can't make a file unreadable under MKS. - echo - echo "+++++++++++++++++++++++++++++++++++" - echo "Read an unreadable file - verify the read fails." - # If the file exists, we try to read it. The - # read will fail. - mkFiles $HOME/jdb.ini - id > $HOME/jdb.ini - chmod a-r $HOME/jdb.ini - if grep -q "uid=" $HOME/jdb.ini ; then - echo "Unable to make file unreadable, so test will fail. chmod: $HOME/jdb.ini" - if grep -q "uid=0" $HOME/jdb.ini ; then - echo "The test is running as root. Fix infrastructure!" - fi - fi +canMakeUnreadable=No +id > $HOME/jdb.ini +if chmod a-r $HOME/jdb.ini +then + grep -q 'uid=0(' $HOME/jdb.ini 2> /dev/null + case $? in + 0) + echo "Error! Can't make file unreadable running as root" + ;; + 1) + echo "Error! Can't make file unreadable for some other reason (windows?)" + ;; + *) + echo "OK. the file is unreadable" + canMakeUnreadable=Yes + ;; + esac +else + echo "Error! Can't create or chmod file" +fi + +if [ "$canMakeUnreadable" = "Yes" ] +then doit failIfNot 1 "open: $HOME/jdb.ini" - clean fi +clean echo @@ -246,8 +256,8 @@ echo "read $fred" > $here/jdb.ini doit failIfNot 1 "from $fred" - if [ ! -r c:/ ] ; then - # Can't make a file unreadable under MKS + if [ "$canMakeUnreadable" = "Yes" ] + then chmod a-r $fred doit failIfNot 1 "open: $fred" From 73a00f6b2f175ec774956e95ab45801c8f59f2c5 Mon Sep 17 00:00:00 2001 From: Aleksei Efimov Date: Mon, 26 Jan 2015 12:17:59 +0300 Subject: [PATCH 34/72] 8062923: XSL: Run-time internal error in 'substring()' 8062924: XSL: wrong answer from substring() function Reviewed-by: joehw --- .../xalan/internal/xsltc/runtime/BasisLibrary.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/BasisLibrary.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/BasisLibrary.java index 74acd2ad341..8d05e9e8cf7 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/BasisLibrary.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/BasisLibrary.java @@ -270,8 +270,8 @@ public final class BasisLibrary { if (Double.isNaN(start)) return(EMPTYSTRING); - final int strlen = value.length(); - int istart = (int)Math.round(start) - 1; + final int strlen = value.length(); + int istart = (int)Math.round(start) - 1; if (istart > strlen) return(EMPTYSTRING); @@ -292,10 +292,11 @@ public final class BasisLibrary { public static String substringF(String value, double start, double length) { if (Double.isInfinite(start) || Double.isNaN(start) || - Double.isNaN(length)) + Double.isNaN(length) || + length < 0) return(EMPTYSTRING); - int istart = (int)Math.round(start) - 1; + int istart = (int)Math.round(start) - 1; final int isum; if (Double.isInfinite(length)) isum = Integer.MAX_VALUE; From 995835697d08c9c343b2a1d8a35eab4522d7b281 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Mon, 26 Jan 2015 10:28:53 +0100 Subject: [PATCH 35/72] 8069261: Create make dependencies on make variable values Reviewed-by: ihse --- common/autoconf/spec.gmk.in | 2 +- make/Images.gmk | 73 ++++++++++++------- make/Main.gmk | 4 +- make/ZipSource.gmk | 2 +- make/common/IdlCompilation.gmk | 2 +- make/common/JavaCompilation.gmk | 59 ++++++++++----- make/common/MakeBase.gmk | 85 ++++++++++++++++++++-- make/common/NativeCompilation.gmk | 64 ++++++++++++----- make/common/TextFileProcessing.gmk | 5 +- test/make/TestJavaCompilation.gmk | 41 ++++++++--- test/make/TestMakeBase.gmk | 112 +++++++++++++++++++++++++++++ 11 files changed, 366 insertions(+), 83 deletions(-) diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 1c6c1c40132..d8b63f4c659 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -243,7 +243,7 @@ MAKESUPPORT_OUTPUTDIR=$(BUILD_OUTPUT)/makesupport HOTSPOT_OUTPUTDIR=$(BUILD_OUTPUT)/hotspot JDK_OUTPUTDIR=$(BUILD_OUTPUT)/jdk IMAGES_OUTPUTDIR=$(BUILD_OUTPUT)/images -TESTMAKE_OUTPUTDIR=$(BUILD_OUTPUT)/testmake +TESTMAKE_OUTPUTDIR=$(BUILD_OUTPUT)/test-make MAKESUPPORT_OUTPUTDIR=$(BUILD_OUTPUT)/make-support HOTSPOT_DIST=@HOTSPOT_DIST@ diff --git a/make/Images.gmk b/make/Images.gmk index 20c5e1011de..5913c0703df 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -111,14 +111,16 @@ DEPENDENCIES := $(call CacheFind, \ # Use this file inside the image as target for make rule JIMAGE_TARGET_FILE := bin/java$(EXE_SUFFIX) -$(JDK_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) +$(JDK_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) \ + $(call DependOnVariable, JDK_MODULES_LIST) $(ECHO) Creating jdk jimage $(RM) -r $(JDK_IMAGE_DIR) $(JDK_SORTED_MODULES) $(JIMAGE_TOOL) --mods $(JDK_MODULES_LIST) --output $(JDK_IMAGE_DIR) \ $(MODULES_XML) > $(JDK_SORTED_MODULES) $(TOUCH) $@ -$(JRE_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) +$(JRE_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) \ + $(call DependOnVariable, JRE_MODULES_LIST) $(ECHO) Creating jre jimage $(RM) -r $(JRE_IMAGE_DIR) $(JRE_SORTED_MODULES) $(JIMAGE_TOOL) --mods $(JRE_MODULES_LIST) --output $(JRE_IMAGE_DIR) \ @@ -131,7 +133,8 @@ JRE_COMPACT3_IMAGE_DIR := $(JRE_IMAGE_DIR)-compact3 COMPACT_EXTRA_MODULES := jdk.localedata jdk.crypto.pkcs11 jdk.crypto.ec -$(JRE_COMPACT1_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) +$(JRE_COMPACT1_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) \ + $(call DependOnVariable, JRE_COMPACT1_MODULES_LIST) $(ECHO) Creating jre compact1 jimage $(RM) -r $(JRE_COMPACT1_IMAGE_DIR) $(JRE_COMPACT1_SORTED_MODULES) $(JIMAGE_TOOL) \ @@ -140,7 +143,8 @@ $(JRE_COMPACT1_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) $(MODULES_XML) > $(JRE_COMPACT1_SORTED_MODULES) $(TOUCH) $@ -$(JRE_COMPACT2_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) +$(JRE_COMPACT2_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) \ + $(call DependOnVariable, JRE_COMPACT2_MODULES_LIST) $(ECHO) Creating jre compact2 jimage $(RM) -r $(JRE_COMPACT2_IMAGE_DIR) $(JRE_COMPACT2_SORTED_MODULES) $(JIMAGE_TOOL) \ @@ -149,7 +153,8 @@ $(JRE_COMPACT2_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) $(MODULES_XML) > $(JRE_COMPACT2_SORTED_MODULES) $(TOUCH) $@ -$(JRE_COMPACT3_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) +$(JRE_COMPACT3_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) \ + $(call DependOnVariable, JRE_COMPACT3_MODULES_LIST) $(ECHO) Creating jre compact3 jimage $(RM) -r $(JRE_COMPACT3_IMAGE_DIR) $(JRE_COMPACT3_SORTED_MODULES) $(JIMAGE_TOOL) \ @@ -368,45 +373,59 @@ JRE_COMPACT3_INFO_FILE := $(JRE_COMPACT3_IMAGE_DIR)/release # Common way to emit a line into the release or info file define info-file-item # name value - $(PRINTF) '%s="%s"\n' $1 $2 >> $@ + $(PRINTF) '%s="%s"\n' $1 $2 >> $@ endef # Param 1 - The file containing the MODULES list define create-info-file - $(ECHO) $(LOG_INFO) Generating $(patsubst $(OUTPUT_ROOT)/%,%,$@) - $(MKDIR) -p $(@D) - $(RM) $@ - $(call info-file-item, "JAVA_VERSION", "$(JDK_VERSION)") - $(call info-file-item, "OS_NAME", "$(REQUIRED_OS_NAME)") - $(call info-file-item, "OS_VERSION", "$(REQUIRED_OS_VERSION)") - $(call info-file-item, "OS_ARCH", "$(OPENJDK_TARGET_CPU_LEGACY)") - $(if $(JDK_ARCH_ABI_PROP_NAME), \ - $(call info-file-item, "SUN_ARCH_ABI", "$(JDK_ARCH_ABI_PROP_NAME)")) - $(call info-file-item, "SOURCE", "$(ALL_SOURCE_TIPS)") - $(call info-file-item, "MODULES", "`$(CAT) $1`") + $(call info-file-item, "JAVA_VERSION", "$(JDK_VERSION)") + $(call info-file-item, "OS_NAME", "$(REQUIRED_OS_NAME)") + $(call info-file-item, "OS_VERSION", "$(REQUIRED_OS_VERSION)") + $(call info-file-item, "OS_ARCH", "$(OPENJDK_TARGET_CPU_LEGACY)") + $(if $(JDK_ARCH_ABI_PROP_NAME), \ + $(call info-file-item, "SUN_ARCH_ABI", "$(JDK_ARCH_ABI_PROP_NAME)")) + $(call info-file-item, "SOURCE", "$(ALL_SOURCE_TIPS)") + $(call info-file-item, "MODULES", "`$(CAT) $1`") endef +# Param 1 - The file containing the MODULES list +define prepare-info-file + $(ECHO) $(LOG_INFO) Generating $(patsubst $(OUTPUT_ROOT)/%,%,$@) + $(MKDIR) -p $(@D) + $(RM) $@ +endef + +define info-file + $(call prepare-info-file, $1) + $(call create-info-file, $1) +endef + +# Create a variable dependency file common for all release info files. The +# sorted module list will only change if the image is regenerated, which will +# trigger a rebuild of these files anyway. +INFO_FILE_VARDEPS := $(call DependOnVariable, create-info-file) + ALL_SOURCE_TIPS = $(shell \ if [ -f $(SUPPORT_OUTPUTDIR)/source_tips ] ; then \ $(CAT) $(SUPPORT_OUTPUTDIR)/source_tips ; \ fi) -$(JRE_INFO_FILE): $(OUTPUT_ROOT)/spec.gmk $(SUPPORT_OUTPUTDIR)/source_tips - $(call create-info-file, $(JRE_SORTED_MODULES)) +$(JRE_INFO_FILE): $(INFO_FILE_VARDEPS) $(SUPPORT_OUTPUTDIR)/source_tips + $(call info-file, $(JRE_SORTED_MODULES)) -$(JDK_INFO_FILE): $(OUTPUT_ROOT)/spec.gmk $(SUPPORT_OUTPUTDIR)/source_tips - $(call create-info-file, $(JDK_SORTED_MODULES)) +$(JDK_INFO_FILE): $(INFO_FILE_VARDEPS) $(SUPPORT_OUTPUTDIR)/source_tips + $(call info-file, $(JDK_SORTED_MODULES)) -$(JRE_COMPACT1_INFO_FILE): $(OUTPUT_ROOT)/spec.gmk $(SUPPORT_OUTPUTDIR)/source_tips - $(call create-info-file, $(JRE_COMPACT1_SORTED_MODULES)) +$(JRE_COMPACT1_INFO_FILE): $(INFO_FILE_VARDEPS) $(SUPPORT_OUTPUTDIR)/source_tips + $(call info-file, $(JRE_COMPACT1_SORTED_MODULES)) $(call info-file-item, "JAVA_PROFILE", "compact1") -$(JRE_COMPACT2_INFO_FILE): $(OUTPUT_ROOT)/spec.gmk $(SUPPORT_OUTPUTDIR)/source_tips - $(call create-info-file, $(JRE_COMPACT2_SORTED_MODULES)) +$(JRE_COMPACT2_INFO_FILE): $(INFO_FILE_VARDEPS) $(SUPPORT_OUTPUTDIR)/source_tips + $(call info-file, $(JRE_COMPACT2_SORTED_MODULES)) $(call info-file-item, "JAVA_PROFILE", "compact2") -$(JRE_COMPACT3_INFO_FILE): $(OUTPUT_ROOT)/spec.gmk $(SUPPORT_OUTPUTDIR)/source_tips - $(call create-info-file, $(JRE_COMPACT3_SORTED_MODULES)) +$(JRE_COMPACT3_INFO_FILE): $(INFO_FILE_VARDEPS) $(SUPPORT_OUTPUTDIR)/source_tips + $(call info-file, $(JRE_COMPACT3_SORTED_MODULES)) $(call info-file-item, "JAVA_PROFILE", "compact3") JRE_TARGETS += $(JRE_INFO_FILE) diff --git a/make/Main.gmk b/make/Main.gmk index a46f1de8508..68542121cca 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -402,6 +402,8 @@ else verify-modules: exploded-image + test-make: clean-test-make + endif ################################################################################ @@ -477,7 +479,7 @@ ALL_TARGETS += default all # file. CLEAN_DIRS += hotspot jdk bootcycle-build test buildtools support \ - images make-support + images make-support test-make CLEAN_DIR_TARGETS := $(addprefix clean-, $(CLEAN_DIRS)) CLEAN_PHASES := gensrc java native include CLEAN_PHASE_TARGETS := $(addprefix clean-, $(CLEAN_PHASES)) diff --git a/make/ZipSource.gmk b/make/ZipSource.gmk index 52bf6aa5149..a83d1d74cbc 100644 --- a/make/ZipSource.gmk +++ b/make/ZipSource.gmk @@ -71,7 +71,7 @@ $(eval $(call SetupCopyFiles,COPY_LAUNCHER_SRC, \ $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_API_DIR)/native/libjli/java_md*))) # This dir needs to exist before macro is evaluated to avoid warning from find. -$(eval $(call MakeDir, $(SUPPORT_OUTPUTDIR)/src)) +$(call MakeDir, $(SUPPORT_OUTPUTDIR)/src) $(eval $(call SetupZipArchive,BUILD_SRC_ZIP, \ SRC := $(SRC_ZIP_SRCS) $(SUPPORT_OUTPUTDIR)/src, \ INCLUDES := $(SRC_ZIP_INCLUDES) launcher, \ diff --git a/make/common/IdlCompilation.gmk b/make/common/IdlCompilation.gmk index 3fdf979d154..f1a2fd92b3f 100644 --- a/make/common/IdlCompilation.gmk +++ b/make/common/IdlCompilation.gmk @@ -99,7 +99,7 @@ define SetupIdlCompilationInner $(if $(16),$(error Internal makefile error: Too many arguments to SetupIdlCompilation, please update IdlCompilation.gmk)) # Find all existing java files and existing class files. - $$(eval $$(call MakeDir,$$($1_BIN))) + $$(call MakeDir,$$($1_BIN)) $1_SRCS := $$(shell find $$($1_SRC) -name "*.idl") $1_BINS := $$(shell find $$($1_BIN) -name "*.java") # Prepend the source/bin path to the filter expressions. diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index a183b30dead..7dfa8140234 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -270,19 +270,37 @@ define SetupArchiveInner $1_JAR_UPDATE_OPTIONS := uf endif + # Include all variables of significance in the vardeps file + $1_VARDEPS := $(JAR) $$($1_JAR_CREATE_OPTIONS) $$($1_MANIFEST) $(RELEASE) $(COMPANY_NAME) \ + $$($1_JARMAIN) $$($1_EXTRA_MANIFEST_ATTR) + $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$(dir $$($1_JAR))_the.$$($1_JARNAME).vardeps) + # Here is the rule that creates/updates the jar file. - $$($1_JAR) : $$($1_DEPS) + $$($1_JAR) : $$($1_DEPS) $$($1_MANIFEST) $$($1_VARDEPS_FILE) $(MKDIR) -p $$($1_BIN) $$($1_GREP_INCLUDE_OUTPUT) $$($1_GREP_EXCLUDE_OUTPUT) - $$(if $$($1_MANIFEST), \ - $(SED) -e "s#@@RELEASE@@#$(RELEASE)#" \ - -e "s#@@COMPANY_NAME@@#$(COMPANY_NAME)#" $$($1_MANIFEST) > $$($1_MANIFEST_FILE) \ + # If the vardeps file is part of the newer prereq list, it means that + # either the jar file does not exist, or we need to recreate it from + # from scratch anyway since a simple update will not catch all the + # potential changes. + $$(if $$(filter $$($1_VARDEPS_FILE) $$($1_MANIFEST), $$?), \ + $$(if $$($1_MANIFEST), \ + $(SED) -e "s#@@RELEASE@@#$(RELEASE)#" \ + -e "s#@@COMPANY_NAME@@#$(COMPANY_NAME)#" $$($1_MANIFEST) > $$($1_MANIFEST_FILE) $$(NEWLINE) \ + , \ + $(RM) $$($1_MANIFEST_FILE) && $(TOUCH) $$($1_MANIFEST_FILE) $$(NEWLINE)) \ + $$(if $$($1_JARMAIN), \ + $(ECHO) "Main-Class: $$(strip $$($1_JARMAIN))" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \ + $$(if $$($1_EXTRA_MANIFEST_ATTR), \ + $(PRINTF) "$$($1_EXTRA_MANIFEST_ATTR)\n" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \ + $(ECHO) Creating $$($1_NAME) $$(NEWLINE) \ + $(JAR) $$($1_JAR_CREATE_OPTIONS) $$@ $$($1_MANIFEST_FILE) $$(NEWLINE) \ + $$($1_SCAPTURE_CONTENTS) \ + $$($1_SCAPTURE_METAINF) \ + $$($1_SUPDATE_CONTENTS) \ + $$($1_JARINDEX) && true \ , \ - $(RM) $$($1_MANIFEST_FILE) && $(TOUCH) $$($1_MANIFEST_FILE)) - $$(if $$($1_JARMAIN),$(ECHO) "Main-Class: $$(strip $$($1_JARMAIN))" >> $$($1_MANIFEST_FILE)) - $$(if $$($1_EXTRA_MANIFEST_ATTR),$(PRINTF) "$$($1_EXTRA_MANIFEST_ATTR)\n" >> $$($1_MANIFEST_FILE)) - $$(if $$(wildcard $$@), \ $(ECHO) Modifying $$($1_NAME) $$(NEWLINE) \ $$($1_CAPTURE_CONTENTS) \ $$($1_CAPTURE_METAINF) \ @@ -294,12 +312,6 @@ define SetupArchiveInner $(ZIP) -q -d $$@ `$(CAT) $$($1_DELETESS_FILE)` ; \ fi $$(NEWLINE) \ $$($1_UPDATE_CONTENTS) true $$(NEWLINE) \ - $$($1_JARINDEX) && true \ - , \ - $(ECHO) Creating $$($1_NAME) && $(JAR) $$($1_JAR_CREATE_OPTIONS) $$@ $$($1_MANIFEST_FILE) $$(NEWLINE) \ - $$($1_SCAPTURE_CONTENTS) \ - $$($1_SCAPTURE_METAINF) \ - $$($1_SUPDATE_CONTENTS) \ $$($1_JARINDEX) && true ) # Add jar to target list @@ -431,7 +443,7 @@ define SetupJavaCompilationInner $1_SRC:=$$(call ADD_SRCS,$$($1_SRC)) # Make sure the dirs exist. $$(foreach d,$$($1_SRC), $$(if $$(wildcard $$d),,$$(error SRC specified to SetupJavaCompilation $1 contains missing directory $$d))) - $$(eval $$(call MakeDir,$$($1_BIN))) + $$(call MakeDir,$$($1_BIN)) # Add all source roots to the find cache since we are likely going to run find # on these more than once. The cache will only be updated if necessary. $$(eval $$(call FillCacheFind,$$($1_SRC))) @@ -535,9 +547,14 @@ define SetupJavaCompilationInner $1_SJAVAC:=$$(subst com.sun.tools.javac.Main,com.sun.tools.sjavac.Main,$$($1_JAVAC)) # Set the $1_REMOTE to spawn a background javac server. - $1_REMOTE:=--server:portfile=$$($1_SJAVAC_PORTFILE),id=$1,sjavac=$$(subst $$(SPACE),%20,$$(subst $$(COMMA),%2C,$$(strip $$($1_SERVER_JVM) $$($1_SJAVAC)))) + $1_REMOTE:=--server:portfile=$$($1_SJAVAC_PORTFILE),id=$1,sjavac=$$(subst \ + $$(SPACE),%20,$$(subst $$(COMMA),%2C,$$(strip $$($1_SERVER_JVM) $$($1_SJAVAC)))) - $$($1_BIN)/_the.$1_batch: $$($1_SRCS) $$($1_DEPENDS) + $1_VARDEPS := $$($1_JVM) $$($1_SJAVAC) $$($1_SJAVAC_ARGS) $$($1_FLAGS) \ + $$($1_HEADERS_ARG) $$($1_BIN) + $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_BIN)/_the.$1.vardeps) + + $$($1_BIN)/_the.$1_batch: $$($1_SRCS) $$($1_DEPENDS) $$($1_VARDEPS_FILE) $(MKDIR) -p $$(@D) $$(dir $$($1_SJAVAC_PORTFILE)) # As a workaround for sjavac not tracking api changed from the classpath, force full # recompile if an external dependency, which is something other than a source @@ -592,8 +609,11 @@ define SetupJavaCompilationInner $1_HEADER_TARGETS := $$($1_HEADERS)/_the.$1_headers endif + $1_VARDEPS := $$($1_JVM) $$($1_JAVAC) $$($1_FLAGS) $$($1_BIN) $$($1_HEADERS_ARG) + $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_BIN)/_the.$1.vardeps) + # When not using sjavac, pass along all sources to javac using an @file. - $$($1_BIN)/_the.$1_batch: $$($1_SRCS) $$($1_DEPENDS) + $$($1_BIN)/_the.$1_batch: $$($1_SRCS) $$($1_DEPENDS) $$($1_VARDEPS_FILE) $(MKDIR) -p $$(@D) $(RM) $$($1_BIN)/_the.$1_batch $$($1_BIN)/_the.$1_batch.tmp $$(call ListPathsSafely,$1_SRCS,\n, >> $$($1_BIN)/_the.$1_batch.tmp) @@ -659,4 +679,5 @@ define SetupJavaCompilationCompileTarget $(if $(findstring yes, $(ENABLE_SJAVAC)), $(strip $2)/_the.$(strip $1)_pubapi, \ $(strip $2)/_the.$(strip $1)_batch) endef -endif + +endif # _JAVA_COMPILATION_GMK diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index b45fd52d5cd..5608090bbf7 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -392,11 +392,9 @@ define EvalDebugWrapper endef # Make directory without forking mkdir if not needed -define MakeDir - ifneq ($$(wildcard $1 $2 $3 $4 $5 $6 $7 $8 $9),$$(strip $1 $2 $3 $4 $5 $6 $7 $8 $9)) - $$(shell $(MKDIR) -p $1 $2 $3 $4 $5 $6 $7 $8 $9) - endif -endef +MakeDir = \ + $(strip $(if $(subst $(wildcard $1 $2 $3 $4 $5 $6 $7 $8 $9),,$(strip $1 $2 $3 $4 $5 $6 $7 $8 $9)),\ + $(shell $(MKDIR) -p $1 $2 $3 $4 $5 $6 $7 $8 $9))) ifeq ($(OPENJDK_TARGET_OS),solaris) # On Solaris, if the target is a symlink and exists, cp won't overwrite. @@ -446,6 +444,9 @@ not-containing = $(strip $(foreach v,$(strip $2),$(if $(findstring $(strip $1),$ # Filter out duplicate sub strings while preserving order. Keeps the first occurance. uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) +# String equals +equals = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + ifneq ($(DISABLE_CACHE_FIND), true) ################################################################################ # In Cygwin, finds are very costly, both because of expensive forks and because @@ -542,6 +543,80 @@ define SetupCopyFiles endef +################################################################################ +# ShellQuote +# +# Quotes a string with single quotes and replaces single quotes with '\'' so +# that the contents survives being given to the shell. + +ShellQuote = \ + $(SQUOTE)$(subst $(SQUOTE),$(SQUOTE)\$(SQUOTE)$(SQUOTE),$(strip $1))$(SQUOTE) + +################################################################################ +# Write to and read from file + +# Param 1 - File to read +ReadFile = \ + $(shell $(CAT) $1) + +# Param 1 - Text to write +# Param 2 - File to write to +# Use printf to get consistent behavior on all platforms. +WriteFile = \ + $(shell $(PRINTF) "%s" $(call ShellQuote, $1) > $2) + +################################################################################ +# DependOnVariable +# +# This macro takes a variable name and puts the value in a file only if the +# value has changed since last. The name of the file is returned. This can be +# used to create rule dependencies on make variable values. The following +# example would get rebuilt if the value of SOME_VAR was changed: +# +# path/to/some-file: $(call DependOnVariable, SOME_VAR) +# echo $(SOME_VAR) > $@ +# +# Note that leading and trailing white space in the value is ignored. +# + +# Defines the sub directory structure to store variable value file in +DependOnVariableDirName = \ + $(strip $(subst $(SRC_ROOT)/,,\ + $(if $(filter /%, $(firstword $(MAKEFILE_LIST))), \ + $(firstword $(MAKEFILE_LIST)), \ + $(CURDIR)/$(firstword $(MAKEFILE_LIST))))) + +# Defines the name of the file to store variable value in. Generates a name +# unless parameter 2 is given. +# Param 1 - Name of variable +# Param 2 - (optional) name of file to store value in +DependOnVariableFileName = \ + $(strip $(if $(strip $2), $2, \ + $(MAKESUPPORT_OUTPUTDIR)/vardeps/$(DependOnVariableDirName)/$(strip $1).vardeps)) + +# Does the actual work with parameters stripped. +# If the file exists AND the contents is the same as the variable, do nothing +# else print a new file. +# Always returns the name of the file where the value was printed. +# Param 1 - Name of variable +# Param 2 - (optional) name of file to store value in +DependOnVariableHelper = \ + $(strip $(if $(and $(wildcard $(call DependOnVariableFileName, $1, $2)),\ + $(call equals, $(strip $($1)), \ + $(call ReadFile, $(call DependOnVariableFileName, $1, $2)))),,\ + $(call MakeDir, $(dir $(call DependOnVariableFileName, $1, $2))) \ + $(if $(findstring $(LOG_LEVEL), trace), \ + $(info Variable $1: $(strip $($1))) \ + $(info File: $(call ReadFile, $(call DependOnVariableFileName, $1, $2)))) \ + $(call WriteFile, $($1), $(call DependOnVariableFileName, $1, $2))) \ + $(call DependOnVariableFileName, $1, $2)) + +# Main macro +# Param 1 - Name of variable +# Param 2 - (optional) name of file to store value in +DependOnVariable = \ + $(call DependOnVariableHelper,$(strip $1),$(strip $2)) + ################################################################################ # Hook to include the corresponding custom file, if present. diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index 9088a61e645..ec9ab9b537d 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -114,7 +114,7 @@ define add_native_source endif endif - $$($1_$2_OBJ) : $2 | $$($1_BUILD_INFO) + $$($1_$2_OBJ) : $2 $$($1_COMPILE_VARDEPS_FILE) | $$($1_BUILD_INFO) $(ECHO) $(LOG_INFO) "Compiling $$(notdir $2) (for $$(notdir $$($1_TARGET)))" ifneq ($(TOOLCHAIN_TYPE), microsoft) # The Solaris studio compiler doesn't output the full path to the object file in the @@ -306,7 +306,7 @@ define SetupNativeCompilationInner endif # Make sure the dirs exist. - $$(eval $$(call MakeDir,$$($1_OBJECT_DIR) $$($1_OUTPUT_DIR))) + $$(call MakeDir,$$($1_OBJECT_DIR) $$($1_OUTPUT_DIR)) $$(foreach d,$$($1_SRC), $$(if $$(wildcard $$d),,$$(error SRC specified to SetupNativeCompilation $1 contains missing directory $$d))) # Find all files in the source trees. Sort to remove duplicates. @@ -426,15 +426,16 @@ define SetupNativeCompilationInner $1_BUILD_INFO := $$($1_OBJECT_DIR)/_build-info.marker - # Setup rule for printing progress info when compiling source files. - # This is a rough heuristic and may not always print accurate information. - $$($1_BUILD_INFO): $$($1_SRCS) - ifeq ($$(wildcard $$($1_TARGET)),) - $(ECHO) 'Creating $$($1_BASENAME) from $$(words $$?) file(s)' - else - $(ECHO) 'Updating $$($1_BASENAME) from $$(words $$?) file(s)' - endif - $(TOUCH) $$@ + # Track variable changes for all variables that affect the compilation command + # lines for all object files in this setup. This includes at least all the + # variables used in the call to add_native_source below. + $1_COMPILE_VARDEPS := $$($1_CFLAGS) $$($1_EXTRA_CFLAGS) $(SYSROOT_CFLAGS) \ + $$($1_CXXFLAGS) $$($1_EXTRA_CXXFLAGS) \ + $$($1_CC) $$($1_CXX) $$($1_OBJC) $$($1_ASFLAGS) \ + $$(foreach s, $$($1_SRCS), \ + $$($1_$$(notdir $$s)_CFLAGS) $$($1_$$(notdir $$s)_CXXFLAGS)) + $1_COMPILE_VARDEPS_FILE := $$(call DependOnVariable, $1_COMPILE_VARDEPS, \ + $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).comp.vardeps) # Now call add_native_source for each source file we are going to compile. $$(foreach p,$$($1_SRCS), \ @@ -444,13 +445,28 @@ define SetupNativeCompilationInner $$($1_CXXFLAGS) $$($1_EXTRA_CXXFLAGS) $(SYSROOT_CFLAGS), \ $$($1_CXX),$$($1_OBJC),$$($1_ASFLAGS)))) + # Setup rule for printing progress info when compiling source files. + # This is a rough heuristic and may not always print accurate information. + $$($1_BUILD_INFO): $$($1_SRCS) $$($1_COMPILE_VARDEPS_FILE) + ifeq ($$(wildcard $$($1_TARGET)),) + $(ECHO) 'Creating $$($1_BASENAME) from $$(words $$(filter-out %.vardeps, $$?)) file(s)' + else + $(ECHO) 'Updating $$($1_BASENAME) from $$(words $$(filter-out %.vardeps, $$?)) file(s)' + endif + $(TOUCH) $$@ + # On windows we need to create a resource file ifeq ($(OPENJDK_TARGET_OS), windows) ifneq (,$$($1_VERSIONINFO_RESOURCE)) $1_RES:=$$($1_OBJECT_DIR)/$$($1_BASENAME).res $1_RES_DEP:=$$($1_RES).d -include $$($1_RES_DEP) - $$($1_RES): $$($1_VERSIONINFO_RESOURCE) + + $1_RES_VARDEPS := $(RC) $$($1_RC_FLAGS) + $1_RES_VARDEPS_FILE := $$(call DependOnVariable, $1_RES_VARDEPS, \ + $$($1_RES).vardeps) + + $$($1_RES): $$($1_VERSIONINFO_RESOURCE) $$($1_RES_VARDEPS_FILE) $(ECHO) $(LOG_INFO) "Compiling resource $$(notdir $$($1_VERSIONINFO_RESOURCE)) (for $$(notdir $$($1_TARGET)))" $(RC) $$($1_RC_FLAGS) $(CC_OUT_OPTION)$$@ $$($1_VERSIONINFO_RESOURCE) # Windows RC compiler does not support -showIncludes, so we mis-use CL for this. @@ -462,7 +478,9 @@ define SetupNativeCompilationInner ifneq (,$$($1_MANIFEST)) $1_GEN_MANIFEST:=$$($1_OBJECT_DIR)/$$($1_PROGRAM).manifest IMVERSIONVALUE:=$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION).$(JDK_UPDATE_VERSION).$(COOKED_BUILD_NUMBER) - $$($1_GEN_MANIFEST): $$($1_MANIFEST) + $1_MANIFEST_VARDEPS_FILE := $$(call DependOnVariable, IMVERSIONVALUE, \ + $$($1_GEN_MANIFEST).vardeps) + $$($1_GEN_MANIFEST): $$($1_MANIFEST) $$($1_MANIFEST_VARDEPS_FILE) $(SED) 's%IMVERSION%$$(IMVERSIONVALUE)%g;s%PROGRAM%$$($1_PROGRAM)%g' $$< > $$@ endif endif @@ -575,8 +593,13 @@ define SetupNativeCompilationInner $1_EXTRA_LDFLAGS_SUFFIX += $(GLOBAL_LDFLAGS_SUFFIX) + $1_VARDEPS := $$($1_LD) $(SYSROOT_LDFLAGS) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) \ + $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX) + $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \ + $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).vardeps) + $$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_REAL_MAPFILE) \ - $$($1_DEBUGINFO_EXTRA_DEPS) + $$($1_DEBUGINFO_EXTRA_DEPS) $$($1_VARDEPS_FILE) $(ECHO) $(LOG_INFO) "Linking $$($1_BASENAME)" $$($1_LD) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $(SYSROOT_LDFLAGS) \ $(LD_OUT_OPTION)$$@ \ @@ -592,8 +615,12 @@ define SetupNativeCompilationInner endif ifneq (,$$($1_STATIC_LIBRARY)) + $1_VARDEPS := $(AR) $$($1_ARFLAGS) $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX) + $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \ + $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).vardeps) + # Generating a static library, ie object file archive. - $$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) + $$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_VARDEPS_FILE) $(ECHO) $(LOG_INFO) "Archiving $$($1_STATIC_LIBRARY)" $(AR) $$($1_ARFLAGS) $(AR_OUT_OPTION)$$($1_TARGET) $$($1_EXPECTED_OBJS) \ $$($1_RES) $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX) @@ -603,8 +630,13 @@ define SetupNativeCompilationInner # A executable binary has been specified, setup the target for it. $1_EXTRA_LDFLAGS_SUFFIX += $(GLOBAL_LDFLAGS_SUFFIX) + $1_VARDEPS := $$($1_LDEXE) $(SYSROOT_LDFLAGS) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) \ + $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX) + $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \ + $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).vardeps) + $$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_GEN_MANIFEST) \ - $$($1_DEBUGINFO_EXTRA_DEPS) + $$($1_DEBUGINFO_EXTRA_DEPS) $$($1_VARDEPS_FILE) $(ECHO) $(LOG_INFO) "Linking executable $$($1_BASENAME)" $$($1_LDEXE) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $(SYSROOT_LDFLAGS) \ $(EXE_OUT_OPTION)$$($1_TARGET) \ diff --git a/make/common/TextFileProcessing.gmk b/make/common/TextFileProcessing.gmk index 466d49aa0ea..cc89c378e37 100644 --- a/make/common/TextFileProcessing.gmk +++ b/make/common/TextFileProcessing.gmk @@ -34,7 +34,7 @@ endif # param 3 = the target base directory # param 4 = the target file name (possibly with a partial path) define SetupSingleTextFileForProcessing - $(strip $3)/$(strip $4): $2 + $(strip $3)/$(strip $4): $2 $$($1_VARDEPS_FILE) $(ECHO) $(LOG_INFO) "Processing $(strip $4)" $(MKDIR) -p '$$(@D)' $(RM) '$$@' '$$@.includes.tmp' '$$@.replacements.tmp' @@ -193,6 +193,9 @@ define SetupTextFileProcessingInner $1_INCLUDES_COMMAND_LINE := $(CAT) endif + $1_VARDEPS := $$($1_INCLUDES_COMMAND_LINE) $$($1_REPLACEMENTS_COMMAND_LINE) + $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS) + # Reset target list before populating it $1 := diff --git a/test/make/TestJavaCompilation.gmk b/test/make/TestJavaCompilation.gmk index c82d2058be2..59f73da91fc 100644 --- a/test/make/TestJavaCompilation.gmk +++ b/test/make/TestJavaCompilation.gmk @@ -50,6 +50,9 @@ JAR1_MANIFEST := $(OUTPUT_DIR)/jar1_manifest clean-jar1: $(RM) -r $(OUTPUT_DIR)/_jar1* $(OUTPUT_DIR)/jar1* +$(JAR1_MANIFEST): | $(OUTPUT_DIR)/_jar1_created + $(ECHO) "Test-Attribute: value" > $(JAR1_MANIFEST) + $(OUTPUT_DIR)/_jar1_created: $(DEPS) $(RM) -r $(JAR1_SRC_ROOT) $(RM) $(JAR1_FILE) @@ -61,7 +64,6 @@ $(OUTPUT_DIR)/_jar1_created: $(DEPS) $(TOUCH) $(JAR1_SRC_ROOT)/dir1/file1.class $(TOUCH) $(JAR1_SRC_ROOT)/dir2/file2.class $(TOUCH) $(JAR1_SRC_ROOT)/META-INF/metafile - $(ECHO) "Test-Attribute: value" > $(JAR1_MANIFEST) $(TOUCH) $@ $(eval $(call SetupArchive,BUILD_JAR1, \ @@ -77,7 +79,7 @@ $(OUTPUT_DIR)/_jar1_verified: $(BUILD_JAR1) $(DIFF) -r $(JAR1_SRC_ROOT)/dir1 $(JAR1_UNZIP)/dir1 $(DIFF) -r $(JAR1_SRC_ROOT)/dir2 $(JAR1_UNZIP)/dir2 $(DIFF) -r $(JAR1_SRC_ROOT)/META-INF/metafile $(JAR1_UNZIP)/META-INF/metafile - if [ "`$(GREP) 'Test-Attribute: value' $(JAR1_MANIFEST)`" = "" ]; then \ + if [ "`$(GREP) 'Test-Attribute: value' $(JAR1_UNZIP)/META-INF/MANIFEST.MF`" = "" ]; then \ $(ECHO) "Could not find Test-Attribute in manifest of $(JAR1_FILE)"; \ exit 1; \ fi @@ -88,7 +90,7 @@ TEST_TARGETS += $(OUTPUT_DIR)/_jar1_verified # Change a source file and call this makefile again to force the jar to be # updated. -$(OUTPUT_DIR)_jar1_updated: $(OUTPUT_DIR)/_jar1_verified +$(OUTPUT_DIR)/_jar1_updated: $(OUTPUT_DIR)/_jar1_verified $(ECHO) updated > $(JAR1_SRC_ROOT)/dir1/file1.class $(ECHO) updated > $(JAR1_SRC_ROOT)/META-INF/metafile $(TOUCH) $(OUTPUT_DIR)/_jar1_created @@ -96,9 +98,26 @@ $(OUTPUT_DIR)_jar1_updated: $(OUTPUT_DIR)/_jar1_verified $(TOUCH) $@ update-jar1: $(OUTPUT_DIR)_jar1_updated -TEST_TARGETS += $(OUTPUT_DIR)_jar1_updated -.PHONY: clean-jar1 create-jar1 update-jar1 +# Change the manifest file and call this makefile again to force the jar +# to be updated +$(OUTPUT_DIR)/_jar1_updated_manifest: $(OUTPUT_DIR)/_jar1_updated + $(ECHO) "Test-Attribute: foobar" > $(JAR1_MANIFEST) + +$(MAKE) -f $(THIS_FILE) $(BUILD_JAR1) + $(RM) -r $(JAR1_UNZIP) + $(MKDIR) -p $(JAR1_UNZIP) + $(CD) $(JAR1_UNZIP) && $(UNZIP) $(JAR1_FILE) $(LOG_DEBUG) + if [ "`$(GREP) 'Test-Attribute: foobar' $(JAR1_UNZIP)/META-INF/MANIFEST.MF`" = "" ]; then \ + $(ECHO) "Could not find Test-Attribute in manifest of $(JAR1_FILE)"; \ + exit 1; \ + fi + $(TOUCH) $@ + +update-jar1-manifest: $(OUTPUT_DIR)/_jar1_updated_manifest + +TEST_TARGETS += $(OUTPUT_DIR)/_jar1_updated $(OUTPUT_DIR)/_jar1_updated_manifest + +.PHONY: clean-jar1 create-jar1 update-jar1 update-jar1-manifest ################################################################################ # Test: jar2 @@ -139,14 +158,14 @@ $(OUTPUT_DIR)/_jar2_verified: $(BUILD_JAR2) create-jar2: $(OUTPUT_DIR)/_jar2_verified TEST_TARGETS += $(OUTPUT_DIR)/_jar2_verified -$(OUTPUT_DIR)_jar2_updated: $(OUTPUT_DIR)/_jar2_verified +$(OUTPUT_DIR)/_jar2_updated: $(OUTPUT_DIR)/_jar2_verified $(ECHO) updated > $(JAR2_SRC_ROOT1)/dir1/file1.class $(TOUCH) $(OUTPUT_DIR)/_jar2_created +$(MAKE) -f $(THIS_FILE) $(OUTPUT_DIR)/_jar2_verified $(TOUCH) $@ -update-jar2: $(OUTPUT_DIR)_jar2_updated -TEST_TARGETS += $(OUTPUT_DIR)_jar2_updated +update-jar2: $(OUTPUT_DIR)/_jar2_updated +TEST_TARGETS += $(OUTPUT_DIR)/_jar2_updated .PHONY: clean-jar2 create-jar2 update-jar2 @@ -200,14 +219,14 @@ $(OUTPUT_DIR)/_jar3_verified: $(BUILD_JAR3) create-jar3: $(OUTPUT_DIR)/_jar3_verified TEST_TARGETS += $(OUTPUT_DIR)/_jar3_verified -$(OUTPUT_DIR)_jar3_updated: $(OUTPUT_DIR)/_jar3_verified +$(OUTPUT_DIR)/_jar3_updated: $(OUTPUT_DIR)/_jar3_verified $(ECHO) updated > $(JAR3_SRC_ROOT2)/extra-file $(TOUCH) $(OUTPUT_DIR)/_jar3_created +$(MAKE) -f $(THIS_FILE) $(OUTPUT_DIR)/_jar3_verified $(TOUCH) $@ -update-jar3: $(OUTPUT_DIR)_jar3_updated -TEST_TARGETS += $(OUTPUT_DIR)_jar3_updated +update-jar3: $(OUTPUT_DIR)/_jar3_updated +TEST_TARGETS += $(OUTPUT_DIR)/_jar3_updated .PHONY: clean-jar3 create-jar3 update-jar3 diff --git a/test/make/TestMakeBase.gmk b/test/make/TestMakeBase.gmk index 809115c3815..3309314652d 100644 --- a/test/make/TestMakeBase.gmk +++ b/test/make/TestMakeBase.gmk @@ -33,7 +33,14 @@ DEPS := $(THIS_FILE) \ $(SRC_ROOT)/make/common/MakeBase.gmk \ # +# On macosx, file system timestamps only have 1 second resultion so must add +# sleeps to properly test dependencies. +ifeq ($(OPENJDK_BUILD_OS), macosx) + SLEEP_ON_MAC := sleep 1 +endif + OUTPUT_DIR := $(TESTMAKE_OUTPUTDIR)/make-base +$(call MakeDir, $(OUTPUT_DIR)) ################################################################################ # Escape $ @@ -55,6 +62,111 @@ $(ESCAPE_DOLLAR_DIR)/_escape_dollar: $(DEPS) TEST_TARGETS += $(ESCAPE_DOLLAR_DIR)/_escape_dollar +################################################################################ +# Test ShellQuote + +SHELL_QUOTE_VALUE := foo '""' "''" bar +SHELL_QUOTE_RESULT := $(shell $(ECHO) $(call ShellQuote, \ + $(SHELL_QUOTE_VALUE))) + +ifneq ($(SHELL_QUOTE_VALUE), $(SHELL_QUOTE_RESULT)) + $(error Expected: >$(SHELL_QUOTE_VALUE)< - Result: >$(SHELL_QUOTE_RESULT)<) +endif + +################################################################################ +# Test read and write to file + +READ_WRITE_FILE := $(OUTPUT_DIR)/read-write +READ_WRITE_VALUE := foo '""' "''" \t\n\\ bar +$(call WriteFile, $(READ_WRITE_VALUE), $(READ_WRITE_FILE)) +READ_WRITE_RESULT := $(call ReadFile, $(READ_WRITE_FILE)) + +ifneq ($(READ_WRITE_VALUE), $(READ_WRITE_RESULT)) + $(error Expected: >$(READ_WRITE_VALUE)< - Result: >$(READ_WRITE_RESULT)<) +endif + +################################################################################ +# Test creating dependencies on make variables + +VARDEP_DIR := $(OUTPUT_DIR)/vardep +VARDEP_SRC_FILE := $(VARDEP_DIR)/src-file +VARDEP_TARGET_FILE := $(VARDEP_DIR)/target-file +VARDEP_FLAG_FILE := $(VARDEP_DIR)/flag-file + +$(VARDEP_DIR)/src-file: + $(MKDIR) -p $(@D) + $(ECHO) "some string XXX" > $@ + +$(VARDEP_TARGET_FILE): $(VARDEP_DIR)/src-file \ + $(call DependOnVariable, VARDEP_TEST_VAR) + $(MKDIR) -p $(@D) + $(SED) -e 's/XXX/$(VARDEP_TEST_VAR)/g' $< > $@ + $(TOUCH) $(VARDEP_FLAG_FILE) + +test-vardep: + $(RM) $(VARDEP_SRC_FILE) $(VARDEP_TARGET_FILE) $(VARDEP_FLAG_FILE) + # + # Simply create the target file and verify that it has the correct value + # + $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR=value1 $(VARDEP_TARGET_FILE) + $(PRINTF) "Expecting value1: %s\n" "`$(CAT) $(VARDEP_DIR)/target-file`" + test "some string value1" = "`$(CAT) $(VARDEP_DIR)/target-file`" + test -e $(VARDEP_FLAG_FILE) + # + # Make the target file again and verify that the value is updated with + # the new value + # + $(SLEEP_ON_MAC) + $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR=value2 $(VARDEP_TARGET_FILE) + $(PRINTF) "Expecting value2: %s\n" "`$(CAT) $(VARDEP_DIR)/target-file`" + test "some string value2" = "`$(CAT) $(VARDEP_DIR)/target-file`" + test -e $(VARDEP_FLAG_FILE) + # + # Make the target again with the same value and verify that the recipe + # was never run by checking that the flag file was not recreated + # + $(SLEEP_ON_MAC) + $(RM) $(VARDEP_FLAG_FILE) + $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR=value2 $(VARDEP_TARGET_FILE) + $(PRINTF) "Expecting value2: %s\n" "`$(CAT) $(VARDEP_DIR)/target-file`" + test "some string value2" = "`$(CAT) $(VARDEP_DIR)/target-file`" + test ! -e $(VARDEP_FLAG_FILE) + # + # Test running with spaces at the end and the middle of the value + # and verify that the file isn't rewritten the second time + # + $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR="value3 foo " $(VARDEP_TARGET_FILE) + $(RM) $(VARDEP_FLAG_FILE) + $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR="value3 foo" $(VARDEP_TARGET_FILE) + test ! -e $(VARDEP_FLAG_FILE) + $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR=" value3 foo" $(VARDEP_TARGET_FILE) + test ! -e $(VARDEP_FLAG_FILE) + +# Test specifying a specific value file to store variable in +VARDEP_VALUE_FILE := $(VARDEP_DIR)/value-file +VARDEP_TEST_VAR2 := value3 + +VARDEP_RETURN_VALUE := $(call DependOnVariable, VARDEP_TEST_VAR2, $(VARDEP_VALUE_FILE)) +ifneq ($(VARDEP_VALUE_FILE), $(VARDEP_RETURN_VALUE)) + $(error Expected: $(VARDEP_VALUE_FILE) - DependOnVariable: $(VARDEP_RETURN_VALUE)) +endif +VARDEP_FILE_CONTENTS := $(shell $(CAT) $(VARDEP_VALUE_FILE)) +ifneq ($(VARDEP_TEST_VAR2), $(VARDEP_FILE_CONTENTS)) + $(error Expected: $(VARDEP_TEST_VAR2) - DependOnVariable file contained: \ + $(VARDEP_FILE_CONTENTS)) +endif + +# Test with a variable value containing some problematic characters +VARDEP_TEST_VAR3 := foo '""' "''" bar +VARDEP_VALUE_FILE := $(call DependOnVariable, VARDEP_TEST_VAR3) +VARDEP_FILE_CONTENTS := $(shell $(CAT) $(VARDEP_VALUE_FILE)) +ifneq ($(VARDEP_TEST_VAR3), $(VARDEP_FILE_CONTENTS)) + $(error Expected: >$(VARDEP_TEST_VAR3)< - DependOnVariable file contained: \ + >$(VARDEP_FILE_CONTENTS)<) +endif + +TEST_TARGETS += test-vardep + ################################################################################ all: $(TEST_TARGETS) From bed1fc268d201fbd7b3b0fce14afce3dc6b17e33 Mon Sep 17 00:00:00 2001 From: Aleksei Efimov Date: Mon, 26 Jan 2015 12:36:37 +0300 Subject: [PATCH 36/72] 8046817: JDK 8 schemagen tool does not generate xsd files for enum types Reviewed-by: joehw, mkos --- .../classes/com/sun/tools/internal/jxc/ap/SchemaGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/jxc/ap/SchemaGenerator.java b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/jxc/ap/SchemaGenerator.java index eef5caf28a6..a15b1453e9f 100644 --- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/jxc/ap/SchemaGenerator.java +++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/jxc/ap/SchemaGenerator.java @@ -135,7 +135,7 @@ public class SchemaGenerator extends AbstractProcessor { private void filterClass(List classes, Collection elements) { for (Element element : elements) { - if (element.getKind().equals(ElementKind.CLASS)) { + if (element.getKind().equals(ElementKind.CLASS) || element.getKind().equals(ElementKind.ENUM)) { classes.add(new Reference((TypeElement) element, processingEnv)); filterClass(classes, ElementFilter.typesIn(element.getEnclosedElements())); } From 1d41a44b78a75f60d778070da669fdca59f30319 Mon Sep 17 00:00:00 2001 From: Katja Kantserova Date: Mon, 26 Jan 2015 13:50:53 +0100 Subject: [PATCH 37/72] 8071324: com/sun/jdi/ConnectedVMs.java should be quarantined Reviewed-by: sla --- jdk/test/ProblemList.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index cbe3f74a044..c83e162b72a 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -298,6 +298,9 @@ com/sun/jdi/RedefinePop.sh generic-all # 8068645 com/sun/jdi/CatchPatternTest.sh generic-all +# 8069402 +com/sun/jdi/ConnectedVMs.java generic-all + ############################################################################ # jdk_util From 50ce50d7bb6b2a6f9be07f5b4bbe2ae29ef81dd5 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Mon, 26 Jan 2015 16:25:26 +0100 Subject: [PATCH 38/72] 8071550: SetupJavaComilation EXCLUDE/INCLUDE/EXCLUDE_FILE do not work on META-INF files Reviewed-by: ihse --- make/common/JavaCompilation.gmk | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index 7dfa8140234..919e15ff4c5 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -487,23 +487,23 @@ define SetupJavaCompilationInner $1_ALL_COPIES += $$(filter $$(addprefix %,$$($1_COPY)),$$($1_ALL_SRCS)) # Copy these explicitly $1_ALL_COPIES += $$($1_COPY_FILES) - # Copy must also respect filters. - ifneq (,$$($1_INCLUDES)) - $1_ALL_COPIES := $$(filter $$($1_SRC_INCLUDES),$$($1_ALL_COPIES)) - endif - ifneq (,$$($1_EXCLUDES)) - $1_ALL_COPIES := $$(filter-out $$($1_SRC_EXCLUDES),$$($1_ALL_COPIES)) - endif - ifneq (,$$($1_EXCLUDE_FILES)) - $1_ALL_COPIES := $$(filter-out $$($1_EXCLUDE_FILES_PATTERN),$$($1_ALL_COPIES)) - endif endif - ifneq (,$$($1_ALL_COPIES)) - # Yep, there are files to be copied! - $1_ALL_COPY_TARGETS:= - $$(foreach i,$$($1_ALL_COPIES),$$(eval $$(call add_file_to_copy,$1,$$i))) - # Now we can depend on $$($1_ALL_COPY_TARGETS) to copy all files! - endif + # Copy must also respect filters. + ifneq (,$$($1_INCLUDES)) + $1_ALL_COPIES := $$(filter $$($1_SRC_INCLUDES),$$($1_ALL_COPIES)) + endif + ifneq (,$$($1_EXCLUDES)) + $1_ALL_COPIES := $$(filter-out $$($1_SRC_EXCLUDES),$$($1_ALL_COPIES)) + endif + ifneq (,$$($1_EXCLUDE_FILES)) + $1_ALL_COPIES := $$(filter-out $$($1_EXCLUDE_FILES_PATTERN),$$($1_ALL_COPIES)) + endif + ifneq (,$$($1_ALL_COPIES)) + # Yep, there are files to be copied! + $1_ALL_COPY_TARGETS:= + $$(foreach i,$$($1_ALL_COPIES),$$(eval $$(call add_file_to_copy,$1,$$i))) + # Now we can depend on $$($1_ALL_COPY_TARGETS) to copy all files! + endif # Find all property files to be copied and cleaned from source to bin. ifneq (,$$($1_CLEAN)$$($1_CLEAN_FILES)) From 3de0140a8895369bbb22e36254071f0408840005 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Mon, 26 Jan 2015 15:46:47 -0800 Subject: [PATCH 39/72] 8068162: jvmtiRedefineClasses.cpp: guarantee(false) failed: OLD and/or OBSOLETE method(s) found Enable the test: java/lang/instrument/IsModifiableClassAgent.java Reviewed-by: coleenp, dcubed --- jdk/test/java/lang/instrument/IsModifiableClassAgent.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jdk/test/java/lang/instrument/IsModifiableClassAgent.java b/jdk/test/java/lang/instrument/IsModifiableClassAgent.java index 31329dfd3a1..bb2130924ba 100644 --- a/jdk/test/java/lang/instrument/IsModifiableClassAgent.java +++ b/jdk/test/java/lang/instrument/IsModifiableClassAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,6 @@ /** * @test - * @ignore JDK-8068162 * @bug 6331574 * @summary test isModifiableClass * @author Robert Field, Sun Microsystems From 3e68a8af37f521fdfbd5815cea537a4ab405003b Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Mon, 26 Jan 2015 17:16:57 -0800 Subject: [PATCH 40/72] 8069269: (spec) Defect in the System.nanoTime spec Change the description of how to compare two nanoTime values. Reviewed-by: martin --- .../share/classes/java/lang/System.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/System.java b/jdk/src/java.base/share/classes/java/lang/System.java index 1871774a022..ee6588491f9 100644 --- a/jdk/src/java.base/share/classes/java/lang/System.java +++ b/jdk/src/java.base/share/classes/java/lang/System.java @@ -376,19 +376,16 @@ public final class System { * the difference between two such values, obtained within the same * instance of a Java virtual machine, is computed. * - *

For example, to measure how long some code takes to execute: - *

 {@code
+     * 

For example, to measure how long some code takes to execute: + *

 {@code
      * long startTime = System.nanoTime();
      * // ... the code being measured ...
-     * long estimatedTime = System.nanoTime() - startTime;}
+ * long elapsedNanos = System.nanoTime() - startTime;}
* - *

To compare two nanoTime values - *

 {@code
-     * long t0 = System.nanoTime();
-     * ...
-     * long t1 = System.nanoTime();}
- * - * one should use {@code t1 - t0 < 0}, not {@code t1 < t0}, + *

To compare elapsed time against a timeout, use

 {@code
+     * if (System.nanoTime() - startTime >= timeoutNanos) ...}
+ * instead of
 {@code
+     * if (System.nanoTime() >= startTime + timeoutNanos) ...}
* because of the possibility of numerical overflow. * * @return the current value of the running Java Virtual Machine's From f6262c1abc87a8201f114b42831a0c2f4c642825 Mon Sep 17 00:00:00 2001 From: Masayoshi Okutsu Date: Tue, 27 Jan 2015 12:59:45 +0900 Subject: [PATCH 41/72] 8065178: test/java/util/ResourceBundle/Bug6287579.java needs update for per language package support Reviewed-by: naoto, peytoia --- .../java/util/ResourceBundle/Bug6287579.java | 107 ------------------ 1 file changed, 107 deletions(-) delete mode 100644 jdk/test/java/util/ResourceBundle/Bug6287579.java diff --git a/jdk/test/java/util/ResourceBundle/Bug6287579.java b/jdk/test/java/util/ResourceBundle/Bug6287579.java deleted file mode 100644 index 43e7e8c2b19..00000000000 --- a/jdk/test/java/util/ResourceBundle/Bug6287579.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/* - * @test - * @bug 6287579 - * @summary Make sure that getContents() of ListResourceBundle subclasses is 'protected' - * and returns a different Object[]][] instance in each invocation. - */ - -import java.lang.reflect.*; -import java.util.*; - -public class Bug6287579 { - static final Locale ROOT = new Locale(""); - - static final String[] baseNames = { - "sun.text.resources.BreakIteratorInfo", - "sun.text.resources.FormatData", - "sun.text.resources.CollationData", - "sun.util.resources.LocaleNames", - "sun.util.resources.TimeZoneNames", - - // Make sure the properties-to-class conversion tool generates - // the proper getContents(). - "sun.awt.resources.awt", - }; - - public static void main(String[] args) throws Exception { - int errors = 0; - - List locales = new ArrayList(); - locales.addAll(Arrays.asList(Locale.getAvailableLocales())); - locales.add(ROOT); - - for (Locale locale : locales) { - for (String base : baseNames) { - String className = getResourceName(base, locale); - errors += checkGetContents(className); - } - } - if (errors > 0) { - throw new RuntimeException(errors + " errors found"); - } - } - - static int checkGetContents(String className) throws Exception { - int err = 0; - try { - Class clazz = Class.forName(className); - Method getContentsMethod = clazz.getDeclaredMethod("getContents", - (Class[]) null); - if (!Modifier.isProtected(getContentsMethod.getModifiers())) { - System.err.println(className + ": not protected"); - err++; - } - getContentsMethod.setAccessible(true); - Object bundle = clazz.newInstance(); - Object o1 = getContentsMethod.invoke(bundle, (Object[]) null); - Object o2 = getContentsMethod.invoke(bundle, (Object[]) null); - if (o1 == o2) { - System.err.println(className + ": same instance returned"); - err++; - } - } catch (ClassNotFoundException ce) { - // Skip nonexistent classes - } catch (NoSuchMethodException me) { - System.out.println(className + ": no declared getContents()"); - } - return err; - } - - static String getResourceName(String base, Locale locale) { - if (locale.equals(ROOT)) { - return base; - } - StringBuilder sb = new StringBuilder(base); - sb.append('_').append(locale.getLanguage()); - if (locale.getCountry().length() > 0 - || locale.getVariant().length() > 0) { - sb.append('_').append(locale.getCountry()); - } - if (locale.getVariant().length() > 0) { - sb.append('_').append(locale.getVariant()); - } - return sb.toString(); - } -} From 873b88dcc9457eab4c294d7307632291f415c87e Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 27 Jan 2015 18:16:27 +0800 Subject: [PATCH 42/72] 8022582: Relax response flags checking in sun.security.krb5.KrbKdcRep.check Reviewed-by: mullan --- .../classes/sun/security/krb5/KrbKdcRep.java | 3 +- .../classes/sun/security/krb5/KrbTgsReq.java | 12 +-- .../krb5/internal/CredentialsUtil.java | 6 ++ jdk/test/sun/security/krb5/auto/Context.java | 8 +- .../security/krb5/auto/ForwardableCheck.java | 81 +++++++++++++++++++ jdk/test/sun/security/krb5/auto/KDC.java | 30 +++++-- 6 files changed, 122 insertions(+), 18 deletions(-) create mode 100644 jdk/test/sun/security/krb5/auto/ForwardableCheck.java diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java index 4c63fe1302c..7bf3ac60c58 100644 --- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java @@ -62,7 +62,8 @@ abstract class KrbKdcRep { throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); } - for (int i = 1; i < 6; i++) { + // We allow KDC to return a non-forwardable ticket if request has -f + for (int i = 2; i < 6; i++) { if (req.reqBody.kdcOptions.get(i) != rep.encKDCRepPart.flags.get(i)) { if (Krb5.DEBUG) { diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java index 45f25e825ce..a8b3404da36 100644 --- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java @@ -149,19 +149,11 @@ public class KrbTgsReq { ctime = KerberosTime.now(); // check if they are valid arguments. The optional fields - // should be consistent with settings in KDCOptions. - - // TODO: Is this necessary? If the TGT is not FORWARDABLE, - // you can still request for a FORWARDABLE ticket, just the - // KDC will give you a non-FORWARDABLE one. Even if you - // cannot use the ticket expected, it still contains info. - // This means there will be problem later. We already have - // flags check in KrbTgsRep. Of course, sometimes the KDC - // will not issue the ticket at all. + // should be consistent with settings in KDCOptions. if (options.get(KDCOptions.FORWARDABLE) && (!(asCreds.flags.get(Krb5.TKT_OPTS_FORWARDABLE)))) { - throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS); + options.set(KDCOptions.FORWARDABLE, false); } if (options.get(KDCOptions.FORWARDED)) { if (!(asCreds.flags.get(KDCOptions.FORWARDABLE))) diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java index b6a36777599..14620e94483 100644 --- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java @@ -58,6 +58,9 @@ public class CredentialsUtil { // TODO: we do not support kerberos referral now throw new KrbException("Cross realm impersonation not supported"); } + if (!ccreds.isForwardable()) { + throw new KrbException("S4U2self needs a FORWARDABLE ticket"); + } KrbTgsReq req = new KrbTgsReq( ccreds, ccreds.getClient(), @@ -68,6 +71,9 @@ public class CredentialsUtil { if (!creds.getClient().equals(client)) { throw new KrbException("S4U2self request not honored by KDC"); } + if (!creds.isForwardable()) { + throw new KrbException("S4U2self ticket must be FORWARDABLE"); + } return creds; } diff --git a/jdk/test/sun/security/krb5/auto/Context.java b/jdk/test/sun/security/krb5/auto/Context.java index 02beb2ef773..e7c601debac 100644 --- a/jdk/test/sun/security/krb5/auto/Context.java +++ b/jdk/test/sun/security/krb5/auto/Context.java @@ -23,6 +23,7 @@ import com.sun.security.auth.module.Krb5LoginModule; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -584,7 +585,12 @@ public class Context { out.name = name + " as " + out.cred.getName().toString(); return out; } catch (PrivilegedActionException pae) { - throw pae.getException(); + Exception e = pae.getException(); + if (e instanceof InvocationTargetException) { + throw (Exception)((InvocationTargetException) e).getTargetException(); + } else { + throw e; + } } } diff --git a/jdk/test/sun/security/krb5/auto/ForwardableCheck.java b/jdk/test/sun/security/krb5/auto/ForwardableCheck.java new file mode 100644 index 00000000000..df6e49ec66b --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/ForwardableCheck.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8022582 + * @summary Relax response flags checking in sun.security.krb5.KrbKdcRep.check. + * @compile -XDignore.symbol.file ForwardableCheck.java + * @run main/othervm ForwardableCheck + */ + +import org.ietf.jgss.GSSException; +import sun.security.jgss.GSSUtil; + +import java.util.Arrays; + +public class ForwardableCheck { + + public static void main(String[] args) throws Exception { + OneKDC kdc = new OneKDC(null); + kdc.writeJAASConf(); + + // USER can impersonate someone else + kdc.setOption(KDC.Option.ALLOW_S4U2SELF, + Arrays.asList(OneKDC.USER + "@" + OneKDC.REALM)); + // USER2 is sensitive + kdc.setOption(KDC.Option.SENSITIVE_ACCOUNTS, + Arrays.asList(OneKDC.USER2 + "@" + OneKDC.REALM)); + + Context c; + + // USER2 is sensitive but it's still able to get a normal ticket + c = Context.fromUserPass(OneKDC.USER2, OneKDC.PASS2, false); + + // ... and connect to another account + c.startAsClient(OneKDC.USER, GSSUtil.GSS_KRB5_MECH_OID); + c.x().requestCredDeleg(true); + c.x().requestMutualAuth(false); + + c.take(new byte[0]); + + if (!c.x().isEstablished()) { + throw new Exception("Context should have been established"); + } + + // ... but will not be able to delegate itself + if (c.x().getCredDelegState()) { + throw new Exception("Impossible"); + } + + // Although USER is allowed to impersonate other people, + // it cannot impersonate USER2 coz it's sensitive. + c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + try { + c.impersonate(OneKDC.USER2); + throw new Exception("Should fail"); + } catch (GSSException e) { + e.printStackTrace(); + } + } +} diff --git a/jdk/test/sun/security/krb5/auto/KDC.java b/jdk/test/sun/security/krb5/auto/KDC.java index 1b2814daf29..117e67655da 100644 --- a/jdk/test/sun/security/krb5/auto/KDC.java +++ b/jdk/test/sun/security/krb5/auto/KDC.java @@ -198,6 +198,10 @@ public class KDC { * Krb5.KDC_ERR_POLICY will be send for S4U2proxy request. */ ALLOW_S4U2PROXY, + /** + * Sensitive accounts can never be delegated. + */ + SENSITIVE_ACCOUNTS, }; static { @@ -643,7 +647,7 @@ public class KDC { try { System.out.println(realm + "> " + tgsReq.reqBody.cname + " sends TGS-REQ for " + - service); + service + ", " + tgsReq.reqBody.kdcOptions); KDCReqBody body = tgsReq.reqBody; int[] eTypes = KDCReqBodyDotEType(body); int e2 = eTypes[0]; // etype for outgoing session key @@ -719,7 +723,13 @@ public class KDC { boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1]; if (body.kdcOptions.get(KDCOptions.FORWARDABLE) && allowForwardable) { - bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; + List sensitives = (List) + options.get(Option.SENSITIVE_ACCOUNTS); + if (sensitives != null && sensitives.contains(cname.toString())) { + // Cannot make FORWARDABLE + } else { + bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; + } } if (body.kdcOptions.get(KDCOptions.FORWARDED) || etp.flags.get(Krb5.TKT_OPTS_FORWARDED)) { @@ -824,7 +834,8 @@ public class KDC { t, edata); System.out.println(" Return " + tgsRep.cname - + " ticket for " + tgsRep.ticket.sname); + + " ticket for " + tgsRep.ticket.sname + ", flags " + + tFlags); DerOutputStream out = new DerOutputStream(); out.write(DerValue.createTag(DerValue.TAG_APPLICATION, @@ -869,7 +880,7 @@ public class KDC { try { System.out.println(realm + "> " + asReq.reqBody.cname + " sends AS-REQ for " + - service); + service + ", " + asReq.reqBody.kdcOptions); KDCReqBody body = asReq.reqBody; @@ -926,7 +937,13 @@ public class KDC { //body.from boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1]; if (body.kdcOptions.get(KDCOptions.FORWARDABLE)) { - bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; + List sensitives = (List) + options.get(Option.SENSITIVE_ACCOUNTS); + if (sensitives != null && sensitives.contains(body.cname.toString())) { + // Cannot make FORWARDABLE + } else { + bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true; + } } if (body.kdcOptions.get(KDCOptions.RENEWABLE)) { bFlags[Krb5.TKT_OPTS_RENEWABLE] = true; @@ -1102,7 +1119,8 @@ public class KDC { edata); System.out.println(" Return " + asRep.cname - + " ticket for " + asRep.ticket.sname); + + " ticket for " + asRep.ticket.sname + ", flags " + + tFlags); DerOutputStream out = new DerOutputStream(); out.write(DerValue.createTag(DerValue.TAG_APPLICATION, From a67e9f2d36923d9aa046716ac23ae46ec655d078 Mon Sep 17 00:00:00 2001 From: Sonali Goel Date: Tue, 27 Jan 2015 15:11:57 -0800 Subject: [PATCH 43/72] 8068463: Group 10c: golden files for tests in tools/javac dir Reviewed-by: jjg, mcimadamore --- .../javac/annotations/6359949/T6359949a.java | 27 ++------------- .../javac/annotations/6359949/T6359949a.out | 2 ++ .../tools/javac/annotations/default/A.java | 33 +++---------------- .../tools/javac/annotations/default/Derr.out | 2 ++ .../tools/javac/annotations/default/Eerr.out | 2 ++ .../test/tools/javac/annotations/neg/Dep.java | 28 ++-------------- .../test/tools/javac/annotations/neg/Dep.out | 4 +++ .../test/tools/javac/lint/Deprecation.java | 27 ++------------- .../test/tools/javac/lint/Deprecation.out | 4 +++ .../test/tools/javac/lint/FallThrough.java | 27 ++------------- .../test/tools/javac/lint/FallThrough.out | 4 +++ .../test/tools/javac/lint/Unchecked.java | 27 ++------------- langtools/test/tools/javac/lint/Unchecked.out | 4 +++ .../test/tools/javac/staticImport/Ambig1.java | 27 ++------------- .../test/tools/javac/staticImport/Ambig1.out | 2 ++ .../javac/staticImport/ImportPrivate.java | 27 ++------------- .../javac/staticImport/ImportPrivate.out | 3 ++ .../staticImport/PrivateStaticImport.java | 27 ++------------- .../staticImport/PrivateStaticImport.out | 2 ++ .../test/tools/javac/staticImport/Shadow.java | 27 ++------------- .../test/tools/javac/staticImport/Shadow.out | 2 ++ .../javac/staticImport/StaticImport2.java | 27 ++------------- .../javac/staticImport/StaticImport2.out | 2 ++ 23 files changed, 57 insertions(+), 280 deletions(-) create mode 100644 langtools/test/tools/javac/annotations/6359949/T6359949a.out create mode 100644 langtools/test/tools/javac/annotations/default/Derr.out create mode 100644 langtools/test/tools/javac/annotations/default/Eerr.out create mode 100644 langtools/test/tools/javac/annotations/neg/Dep.out create mode 100644 langtools/test/tools/javac/lint/Deprecation.out create mode 100644 langtools/test/tools/javac/lint/FallThrough.out create mode 100644 langtools/test/tools/javac/lint/Unchecked.out create mode 100644 langtools/test/tools/javac/staticImport/Ambig1.out create mode 100644 langtools/test/tools/javac/staticImport/ImportPrivate.out create mode 100644 langtools/test/tools/javac/staticImport/PrivateStaticImport.out create mode 100644 langtools/test/tools/javac/staticImport/Shadow.out create mode 100644 langtools/test/tools/javac/staticImport/StaticImport2.out diff --git a/langtools/test/tools/javac/annotations/6359949/T6359949a.java b/langtools/test/tools/javac/annotations/6359949/T6359949a.java index 0dd9966197e..aa0f90a38a7 100644 --- a/langtools/test/tools/javac/annotations/6359949/T6359949a.java +++ b/langtools/test/tools/javac/annotations/6359949/T6359949a.java @@ -1,31 +1,8 @@ /* - * Copyright (c) 2006, 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test + * @test /nodynamiccopyright/ * @bug 6359949 * @summary (at)Override of static shouldn't be accepted (compiler shouldissue an error/warning) - * @compile/fail T6359949a.java + * @compile/fail/ref=T6359949a.out -XDrawDiagnostics T6359949a.java */ class Example { diff --git a/langtools/test/tools/javac/annotations/6359949/T6359949a.out b/langtools/test/tools/javac/annotations/6359949/T6359949a.out new file mode 100644 index 00000000000..b7119189fe5 --- /dev/null +++ b/langtools/test/tools/javac/annotations/6359949/T6359949a.out @@ -0,0 +1,2 @@ +T6359949a.java:15:5: compiler.err.method.does.not.override.superclass +1 error diff --git a/langtools/test/tools/javac/annotations/default/A.java b/langtools/test/tools/javac/annotations/default/A.java index 99c8e5efd1d..72834f60092 100644 --- a/langtools/test/tools/javac/annotations/default/A.java +++ b/langtools/test/tools/javac/annotations/default/A.java @@ -1,37 +1,12 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test + * @test /nodynamiccopyright/ * @bug 4901262 * @summary Constraints regarding annotation defaults * @author gafter * - * @compile A.java - * @compile B.java - * @compile C.java - * @compile/fail Derr.java - * @compile/fail Eerr.java + * @compile A.java B.java C.java + * @compile/fail/ref=Derr.out -XDrawDiagnostics Derr.java + * @compile/fail/ref=Eerr.out -XDrawDiagnostics Eerr.java */ public @interface A { diff --git a/langtools/test/tools/javac/annotations/default/Derr.out b/langtools/test/tools/javac/annotations/default/Derr.out new file mode 100644 index 00000000000..ed61b90e577 --- /dev/null +++ b/langtools/test/tools/javac/annotations/default/Derr.out @@ -0,0 +1,2 @@ +Derr.java:24:1: compiler.err.annotation.missing.default.value: A, x +1 error diff --git a/langtools/test/tools/javac/annotations/default/Eerr.out b/langtools/test/tools/javac/annotations/default/Eerr.out new file mode 100644 index 00000000000..b443906fe10 --- /dev/null +++ b/langtools/test/tools/javac/annotations/default/Eerr.out @@ -0,0 +1,2 @@ +Eerr.java:24:9: compiler.err.duplicate.annotation.member.value: x, A +1 error diff --git a/langtools/test/tools/javac/annotations/neg/Dep.java b/langtools/test/tools/javac/annotations/neg/Dep.java index ff83dc761fd..4bac69cf2c4 100644 --- a/langtools/test/tools/javac/annotations/neg/Dep.java +++ b/langtools/test/tools/javac/annotations/neg/Dep.java @@ -1,34 +1,10 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test + * @test /nodynamiccopyright/ * @bug 4903501 * @summary Please add annotation Deprecated to supplant the javadoc tag * @author gafter * - * @compile/fail -Xlint:dep-ann -Werror Dep.java - * @compile -Xlint:dep-ann Dep.java + * @compile/fail/ref=Dep.out -XDrawDiagnostics -Xlint:dep-ann -Werror Dep.java */ /** @deprecated */ diff --git a/langtools/test/tools/javac/annotations/neg/Dep.out b/langtools/test/tools/javac/annotations/neg/Dep.out new file mode 100644 index 00000000000..263529bec9e --- /dev/null +++ b/langtools/test/tools/javac/annotations/neg/Dep.out @@ -0,0 +1,4 @@ +Dep.java:11:1: compiler.warn.missing.deprecated.annotation +- compiler.err.warnings.and.werror +1 error +1 warning diff --git a/langtools/test/tools/javac/lint/Deprecation.java b/langtools/test/tools/javac/lint/Deprecation.java index 60f185c6bdb..9350535e41d 100644 --- a/langtools/test/tools/javac/lint/Deprecation.java +++ b/langtools/test/tools/javac/lint/Deprecation.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test + * @test /nodynamiccopyright/ * @bug 4821359 * @summary Add -Xlint flag * @author gafter * - * @compile/fail -Xlint:deprecation -Werror Deprecation.java + * @compile/fail/ref=Deprecation.out -XDrawDiagnostics -Xlint:deprecation -Werror Deprecation.java */ /** @deprecated */ diff --git a/langtools/test/tools/javac/lint/Deprecation.out b/langtools/test/tools/javac/lint/Deprecation.out new file mode 100644 index 00000000000..c16983bc6c1 --- /dev/null +++ b/langtools/test/tools/javac/lint/Deprecation.out @@ -0,0 +1,4 @@ +Deprecation.java:14:17: compiler.warn.has.been.deprecated: A, compiler.misc.unnamed.package +- compiler.err.warnings.and.werror +1 error +1 warning diff --git a/langtools/test/tools/javac/lint/FallThrough.java b/langtools/test/tools/javac/lint/FallThrough.java index 47e277492d2..e70bd67a552 100644 --- a/langtools/test/tools/javac/lint/FallThrough.java +++ b/langtools/test/tools/javac/lint/FallThrough.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test + * @test /nodynamiccopyright/ * @bug 4821359 4981267 * @summary Add -Xlint flag * @author gafter * - * @compile/fail -Xlint:fallthrough -Werror FallThrough.java + * @compile/fail/ref=FallThrough.out -XDrawDiagnostics -Xlint:fallthrough -Werror FallThrough.java */ class FallThrough { diff --git a/langtools/test/tools/javac/lint/FallThrough.out b/langtools/test/tools/javac/lint/FallThrough.out new file mode 100644 index 00000000000..2a76c4d9cbf --- /dev/null +++ b/langtools/test/tools/javac/lint/FallThrough.out @@ -0,0 +1,4 @@ +FallThrough.java:16:9: compiler.warn.possible.fall-through.into.case +- compiler.err.warnings.and.werror +1 error +1 warning diff --git a/langtools/test/tools/javac/lint/Unchecked.java b/langtools/test/tools/javac/lint/Unchecked.java index 4944f643f9e..4e994158721 100644 --- a/langtools/test/tools/javac/lint/Unchecked.java +++ b/langtools/test/tools/javac/lint/Unchecked.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test + * @test /nodynamiccopyright/ * @bug 4821359 * @summary Add -Xlint flag * @author gafter * - * @compile/fail -Xlint:unchecked -Werror Unchecked.java + * @compile/fail/ref=Unchecked.out -XDrawDiagnostics -Xlint:unchecked -Werror Unchecked.java */ class Unchecked { diff --git a/langtools/test/tools/javac/lint/Unchecked.out b/langtools/test/tools/javac/lint/Unchecked.out new file mode 100644 index 00000000000..6fe9e2e7f2f --- /dev/null +++ b/langtools/test/tools/javac/lint/Unchecked.out @@ -0,0 +1,4 @@ +Unchecked.java:12:32: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), Unchecked, Unchecked +- compiler.err.warnings.and.werror +1 error +1 warning diff --git a/langtools/test/tools/javac/staticImport/Ambig1.java b/langtools/test/tools/javac/staticImport/Ambig1.java index 20b1ff7e7f5..3aa03d99e7c 100644 --- a/langtools/test/tools/javac/staticImport/Ambig1.java +++ b/langtools/test/tools/javac/staticImport/Ambig1.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test + * @test /nodynamiccopyright/ * @bug 4929736 * @summary Missing ambiguity error when two methods are equally specific * @author gafter * - * @compile/fail Ambig1.java + * @compile/fail/ref=Ambig1.out -XDrawDiagnostics Ambig1.java */ package ambig1; diff --git a/langtools/test/tools/javac/staticImport/Ambig1.out b/langtools/test/tools/javac/staticImport/Ambig1.out new file mode 100644 index 00000000000..47c269bb316 --- /dev/null +++ b/langtools/test/tools/javac/staticImport/Ambig1.out @@ -0,0 +1,2 @@ +Ambig1.java:24:9: compiler.err.ref.ambiguous: f, kindname.method, f(int), ambig1.B, kindname.method, f(int), ambig1.A +1 error diff --git a/langtools/test/tools/javac/staticImport/ImportPrivate.java b/langtools/test/tools/javac/staticImport/ImportPrivate.java index 366f2278656..b108d498f4e 100644 --- a/langtools/test/tools/javac/staticImport/ImportPrivate.java +++ b/langtools/test/tools/javac/staticImport/ImportPrivate.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test + * @test /nodynamiccopyright/ * @bug 4979456 * @summary NPE while compiling static import of inaccessible class member * @author gafter * - * @compile/fail ImportPrivate.java + * @compile/fail/ref=ImportPrivate.out -XDrawDiagnostics ImportPrivate.java */ package importPrivate; diff --git a/langtools/test/tools/javac/staticImport/ImportPrivate.out b/langtools/test/tools/javac/staticImport/ImportPrivate.out new file mode 100644 index 00000000000..ba382b905f8 --- /dev/null +++ b/langtools/test/tools/javac/staticImport/ImportPrivate.out @@ -0,0 +1,3 @@ +ImportPrivate.java:12:1: compiler.err.cant.resolve.location: kindname.static, m, , , kindname.class, importPrivate.A +ImportPrivate.java:22:9: compiler.err.cant.resolve.location.args: kindname.method, m, , , (compiler.misc.location: kindname.class, importPrivate.MyTest, null) +2 errors diff --git a/langtools/test/tools/javac/staticImport/PrivateStaticImport.java b/langtools/test/tools/javac/staticImport/PrivateStaticImport.java index 05e73490ebe..dd433f1c543 100644 --- a/langtools/test/tools/javac/staticImport/PrivateStaticImport.java +++ b/langtools/test/tools/javac/staticImport/PrivateStaticImport.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test + * @test /nodynamiccopyright/ * @bug 4912075 * @summary static import of private field crashes compiler * @author gafter * - * @compile/fail PrivateStaticImport.java + * @compile/fail/ref=PrivateStaticImport.out -XDrawDiagnostics PrivateStaticImport.java */ package psi; diff --git a/langtools/test/tools/javac/staticImport/PrivateStaticImport.out b/langtools/test/tools/javac/staticImport/PrivateStaticImport.out new file mode 100644 index 00000000000..b60a3018859 --- /dev/null +++ b/langtools/test/tools/javac/staticImport/PrivateStaticImport.out @@ -0,0 +1,2 @@ +PrivateStaticImport.java:18:17: compiler.err.cant.resolve.location: kindname.variable, FOO_VALUE, , , (compiler.misc.location: kindname.class, psi.Bar, null) +1 error diff --git a/langtools/test/tools/javac/staticImport/Shadow.java b/langtools/test/tools/javac/staticImport/Shadow.java index 3117a2db929..07feacab2f4 100644 --- a/langtools/test/tools/javac/staticImport/Shadow.java +++ b/langtools/test/tools/javac/staticImport/Shadow.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test + * @test /nodynamiccopyright/ * @bug 5017254 * @summary compiler fails to shadow inapplicable method with static import * @author gafter * - * @compile/fail Shadow.java + * @compile/fail/ref=Shadow.out -XDrawDiagnostics Shadow.java */ package shadow; diff --git a/langtools/test/tools/javac/staticImport/Shadow.out b/langtools/test/tools/javac/staticImport/Shadow.out new file mode 100644 index 00000000000..8106a5d6fef --- /dev/null +++ b/langtools/test/tools/javac/staticImport/Shadow.out @@ -0,0 +1,2 @@ +Shadow.java:25:9: compiler.err.cant.apply.symbol: kindname.method, m1, int, compiler.misc.no.args, kindname.class, shadow.T2, (compiler.misc.arg.length.mismatch) +1 error diff --git a/langtools/test/tools/javac/staticImport/StaticImport2.java b/langtools/test/tools/javac/staticImport/StaticImport2.java index b65ee8a70d5..b4e79473735 100644 --- a/langtools/test/tools/javac/staticImport/StaticImport2.java +++ b/langtools/test/tools/javac/staticImport/StaticImport2.java @@ -1,33 +1,10 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test + * @test /nodynamiccopyright/ * @bug 4855358 * @summary add support for JSR 201's static import facility * @author gafter * - * @compile/fail StaticImport2.java + * @compile/fail/ref=StaticImport2.out -XDrawDiagnostics StaticImport2.java */ package p; diff --git a/langtools/test/tools/javac/staticImport/StaticImport2.out b/langtools/test/tools/javac/staticImport/StaticImport2.out new file mode 100644 index 00000000000..5426a5db394 --- /dev/null +++ b/langtools/test/tools/javac/staticImport/StaticImport2.out @@ -0,0 +1,2 @@ +StaticImport2.java:24:17: compiler.err.ref.ambiguous: K, kindname.variable, K, p.B, kindname.variable, K, p.A +1 error From 5035f5b1d41e0b6944f6c42f70791b3e198232be Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Tue, 27 Jan 2015 19:50:41 -0800 Subject: [PATCH 44/72] 8068937: jdeps shows "not found" if target class has no reference other than its own package Reviewed-by: alanb --- .../classes/com/sun/tools/jdeps/Analyzer.java | 2 +- .../classes/com/sun/tools/jdeps/Archive.java | 17 +++---- .../com/sun/tools/jdeps/JdepsTask.java | 46 ++++++++++++++----- langtools/test/tools/jdeps/Basic.java | 16 ++++++- langtools/test/tools/jdeps/p/C.java | 30 ++++++++++++ langtools/test/tools/jdeps/p/SubClass.java | 28 +++++++++++ langtools/test/tools/jdeps/q/Gee.java | 27 +++++++++++ 7 files changed, 141 insertions(+), 25 deletions(-) create mode 100644 langtools/test/tools/jdeps/p/C.java create mode 100644 langtools/test/tools/jdeps/p/SubClass.java create mode 100644 langtools/test/tools/jdeps/q/Gee.java diff --git a/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/Analyzer.java b/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/Analyzer.java index d69b8019cc8..030619a0744 100644 --- a/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/Analyzer.java +++ b/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/Analyzer.java @@ -218,7 +218,7 @@ public class Analyzer { Archive targetArchive = findArchive(t); if (filter.accepts(o, archive, t, targetArchive)) { addDep(o, t); - if (!requires.contains(targetArchive)) { + if (archive != targetArchive && !requires.contains(targetArchive)) { requires.add(targetArchive); } } diff --git a/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/Archive.java b/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/Archive.java index 49e827c4bff..74b7b57e862 100644 --- a/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/Archive.java +++ b/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/Archive.java @@ -75,20 +75,11 @@ public class Archive { } public void addClass(Location origin) { - Set set = deps.get(origin); - if (set == null) { - set = new HashSet<>(); - deps.put(origin, set); - } + deps.computeIfAbsent(origin, _k -> new HashSet<>()); } public void addClass(Location origin, Location target) { - Set set = deps.get(origin); - if (set == null) { - set = new HashSet<>(); - deps.put(origin, set); - } - set.add(target); + deps.computeIfAbsent(origin, _k -> new HashSet<>()).add(target); } public Set getClasses() { @@ -115,6 +106,10 @@ public class Archive { return filename; } + public Path path() { + return path; + } + interface Visitor { void visit(Location origin, Location target); } diff --git a/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/JdepsTask.java b/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/JdepsTask.java index a430df9b2ae..c76bc6c3ea8 100644 --- a/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/JdepsTask.java +++ b/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/JdepsTask.java @@ -611,6 +611,9 @@ class JdepsTask { deque.add(cn); } a.addClass(d.getOrigin(), d.getTarget()); + } else { + // ensure that the parsed class is added the archive + a.addClass(d.getOrigin()); } } for (String name : a.reader().skippedEntries()) { @@ -643,6 +646,7 @@ class JdepsTask { // if name is a fully-qualified class name specified // from command-line, this class might already be parsed doneClasses.add(classFileName); + for (Dependency d : finder.findDependencies(cf)) { if (depth == 0) { // ignore the dependency @@ -654,6 +658,9 @@ class JdepsTask { if (!doneClasses.contains(cn) && !deque.contains(cn)) { deque.add(cn); } + } else { + // ensure that the parsed class is added the archive + a.addClass(d.getOrigin()); } } } @@ -809,36 +816,53 @@ class JdepsTask { } } - private List getClassPathArchives(String paths) throws IOException { + /* + * Returns the list of Archive specified in cpaths and not included + * initialArchives + */ + private List getClassPathArchives(String cpaths) + throws IOException + { List result = new ArrayList<>(); - if (paths.isEmpty()) { + if (cpaths.isEmpty()) { return result; } - for (String p : paths.split(File.pathSeparator)) { + List paths = new ArrayList<>(); + for (String p : cpaths.split(File.pathSeparator)) { if (p.length() > 0) { - List files = new ArrayList<>(); // wildcard to parse all JAR files e.g. -classpath dir/* int i = p.lastIndexOf(".*"); if (i > 0) { Path dir = Paths.get(p.substring(0, i)); try (DirectoryStream stream = Files.newDirectoryStream(dir, "*.jar")) { for (Path entry : stream) { - files.add(entry); + paths.add(entry); } } } else { - files.add(Paths.get(p)); - } - for (Path f : files) { - if (Files.exists(f)) { - result.add(Archive.getInstance(f)); - } + paths.add(Paths.get(p)); } } } + for (Path path : paths) { + boolean found = initialArchives.stream() + .map(Archive::path) + .anyMatch(p -> isSameFile(path, p)); + if (!found && Files.exists(path)) { + result.add(Archive.getInstance(path)); + } + } return result; } + private boolean isSameFile(Path p1, Path p2) { + try { + return Files.isSameFile(p1, p2); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + class RawOutputFormatter implements Analyzer.Visitor { private final PrintWriter writer; private String pkg = ""; diff --git a/langtools/test/tools/jdeps/Basic.java b/langtools/test/tools/jdeps/Basic.java index a1bfdd4ea31..dcdfd46e0a3 100644 --- a/langtools/test/tools/jdeps/Basic.java +++ b/langtools/test/tools/jdeps/Basic.java @@ -23,9 +23,9 @@ /* * @test - * @bug 8003562 8005428 8015912 8027481 8048063 + * @bug 8003562 8005428 8015912 8027481 8048063 8068937 * @summary Basic tests for jdeps tool - * @build Test p.Foo p.Bar javax.activity.NotCompactProfile + * @build Test p.Foo p.Bar p.C p.SubClass q.Gee javax.activity.NotCompactProfile * @run main Basic */ @@ -90,6 +90,18 @@ public class Basic { new String[] {"compact1"}, new String[] {"-verbose:package", "-e", "java\\.lang\\..*"}); + // parse p.C, p.SubClass and q.* + // p.SubClass have no dependency other than p.C + // q.Gee depends on p.SubClass that should be found + test(testDir, + new String[] {"java.lang", "p"}, + new String[] {"compact1", testDir.getName()}, + new String[] {"-include", "p.C|p.SubClass|q\\..*"}); + test(testDir, + new String[] {"java.lang", "p"}, + new String[] {"compact1", testDir.getName()}, + new String[] {"-classpath", testDir.getPath(), "-include", "p.C|p.SubClass|q\\..*"}); + // test -classpath and -include options test(null, new String[] {"java.lang", "java.util", "java.lang.management", diff --git a/langtools/test/tools/jdeps/p/C.java b/langtools/test/tools/jdeps/p/C.java new file mode 100644 index 00000000000..6ad931824ad --- /dev/null +++ b/langtools/test/tools/jdeps/p/C.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015, 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 p; + +public class C { + public String name() { + return "C"; + } +} diff --git a/langtools/test/tools/jdeps/p/SubClass.java b/langtools/test/tools/jdeps/p/SubClass.java new file mode 100644 index 00000000000..020953d8fa6 --- /dev/null +++ b/langtools/test/tools/jdeps/p/SubClass.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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 p; + +// SubClass only references types in package p +public class SubClass extends C { +} diff --git a/langtools/test/tools/jdeps/q/Gee.java b/langtools/test/tools/jdeps/q/Gee.java new file mode 100644 index 00000000000..0db04fb7bd9 --- /dev/null +++ b/langtools/test/tools/jdeps/q/Gee.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, 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 q; + +public class Gee extends p.SubClass { +} From 54b2d15c941fe076f196c52081b5c83723056a51 Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Tue, 27 Jan 2015 22:01:46 -0800 Subject: [PATCH 45/72] 8054196: XPath: support any type Reviewed-by: alanb, lancea, dfuchs --- .../internal/jaxp/XPathExpressionImpl.java | 354 +++---------- .../apache/xpath/internal/jaxp/XPathImpl.java | 497 ++++-------------- .../xpath/internal/jaxp/XPathImplUtil.java | 262 +++++++++ .../xpath/internal/jaxp/XPathNodesImpl.java | 93 ++++ .../xpath/internal/jaxp/XPathResultImpl.java | 201 +++++++ .../share/classes/javax/xml/xpath/XPath.java | 401 ++++++++++---- .../xml/xpath/XPathEvaluationResult.java | 130 +++++ .../javax/xml/xpath/XPathExpression.java | 276 ++++++++-- .../classes/javax/xml/xpath/XPathFactory.java | 2 +- .../javax/xml/xpath/XPathFactoryFinder.java | 6 +- .../classes/javax/xml/xpath/XPathNodes.java | 65 +++ .../classes/javax/xml/xpath/package.html | 236 ++++++--- .../javax/xml/xpath/XPathAnyTypeTest.java | 190 +++++++ .../javax/xml/xpath/XPathExpAnyTypeTest.java | 176 +++++++ .../javax/xml/xpath/XPathTestBase.java | 140 +++++ 15 files changed, 2121 insertions(+), 908 deletions(-) create mode 100644 jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java create mode 100644 jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java create mode 100644 jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathResultImpl.java create mode 100644 jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java create mode 100644 jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java create mode 100644 jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathAnyTypeTest.java create mode 100644 jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathExpAnyTypeTest.java create mode 100644 jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathTestBase.java diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java index dc64401eda6..a87728dc639 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java @@ -1,15 +1,15 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. */ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,36 +17,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// $Id: XPathExpressionImpl.java,v 1.3 2005/09/27 09:40:43 sunithareddy Exp $ package com.sun.org.apache.xpath.internal.jaxp; -import com.sun.org.apache.xpath.internal.*; -import javax.xml.transform.TransformerException; - -import com.sun.org.apache.xpath.internal.objects.XObject; -import com.sun.org.apache.xml.internal.dtm.DTM; -import com.sun.org.apache.xml.internal.utils.PrefixResolver; -import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; -import com.sun.org.apache.xalan.internal.res.XSLMessages; -import com.sun.org.apache.xalan.internal.utils.FactoryImpl; import com.sun.org.apache.xalan.internal.utils.FeatureManager; - -import javax.xml.namespace.NamespaceContext; +import com.sun.org.apache.xpath.internal.objects.XObject; import javax.xml.namespace.QName; -import javax.xml.xpath.XPathExpressionException; +import javax.xml.transform.TransformerException; import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathEvaluationResult; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFunctionResolver; import javax.xml.xpath.XPathVariableResolver; -import javax.xml.xpath.XPathConstants; - -import org.w3c.dom.Node; import org.w3c.dom.Document; -import org.w3c.dom.DOMImplementation; -import org.w3c.dom.traversal.NodeIterator; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.DocumentBuilder; - +import org.w3c.dom.Node; import org.xml.sax.InputSource; /** @@ -54,22 +39,10 @@ import org.xml.sax.InputSource; * * @author Ramesh Mandava */ -public class XPathExpressionImpl implements javax.xml.xpath.XPathExpression{ +public class XPathExpressionImpl extends XPathImplUtil implements XPathExpression { - private XPathFunctionResolver functionResolver; - private XPathVariableResolver variableResolver; - private JAXPPrefixResolver prefixResolver; private com.sun.org.apache.xpath.internal.XPath xpath; - // By default Extension Functions are allowed in XPath Expressions. If - // Secure Processing Feature is set on XPathFactory then the invocation of - // extensions function need to throw XPathFunctionException - private boolean featureSecureProcessing = false; - - private boolean useServicesMechanism = true; - - private final FeatureManager featureManager; - /** Protected constructor to prevent direct instantiation; use compile() * from the context. */ @@ -81,7 +54,7 @@ public class XPathExpressionImpl implements javax.xml.xpath.XPathExpression{ protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, JAXPPrefixResolver prefixResolver, XPathFunctionResolver functionResolver, - XPathVariableResolver variableResolver ) { + XPathVariableResolver variableResolver) { this(xpath, prefixResolver, functionResolver, variableResolver, false, true, new FeatureManager()); }; @@ -89,291 +62,108 @@ public class XPathExpressionImpl implements javax.xml.xpath.XPathExpression{ protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, JAXPPrefixResolver prefixResolver,XPathFunctionResolver functionResolver, XPathVariableResolver variableResolver, boolean featureSecureProcessing, - boolean useServicesMechanism, FeatureManager featureManager ) { + boolean useServiceMechanism, FeatureManager featureManager) { this.xpath = xpath; this.prefixResolver = prefixResolver; this.functionResolver = functionResolver; this.variableResolver = variableResolver; this.featureSecureProcessing = featureSecureProcessing; - this.useServicesMechanism = useServicesMechanism; + this.useServiceMechanism = useServiceMechanism; this.featureManager = featureManager; }; - public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath ) { + public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath) { this.xpath = xpath; } public Object eval(Object item, QName returnType) throws javax.xml.transform.TransformerException { - XObject resultObject = eval ( item ); - return getResultAsType( resultObject, returnType ); + XObject resultObject = eval(item, xpath); + return getResultAsType(resultObject, returnType); } - private XObject eval ( Object contextItem ) - throws javax.xml.transform.TransformerException { - com.sun.org.apache.xpath.internal.XPathContext xpathSupport = null; - if ( functionResolver != null ) { - JAXPExtensionsProvider jep = new JAXPExtensionsProvider( - functionResolver, featureSecureProcessing, featureManager ); - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext( jep ); - } else { - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); - } - - xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); - XObject xobj = null; - - Node contextNode = (Node)contextItem; - // We always need to have a ContextNode with Xalan XPath implementation - // To allow simple expression evaluation like 1+1 we are setting - // dummy Document as Context Node - - if ( contextNode == null ) - xobj = xpath.execute(xpathSupport, DTM.NULL, prefixResolver); - else - xobj = xpath.execute(xpathSupport, contextNode, prefixResolver); - - return xobj; - } - - - /** - *

Evaluate the compiled XPath expression in the specified context and - * return the result as the specified type.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If returnType is not one of the types defined - * in {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

- * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If returnType is null, then a - * NullPointerException is thrown.

- * - * @param item The starting context (node or node list, for example). - * @param returnType The desired return type. - * - * @return The Object that is the result of evaluating the - * expression and converting the result to - * returnType. - * - * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one - * of the types defined in {@link XPathConstants}. - * @throws NullPointerException If returnType is - * null. - */ + @Override public Object evaluate(Object item, QName returnType) throws XPathExpressionException { - //Validating parameters to enforce constraints defined by JAXP spec - if ( returnType == null ) { - //Throwing NullPointerException as defined in spec - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"returnType"} ); - throw new NullPointerException( fmsg ); - } - // Checking if requested returnType is supported. returnType need to be - // defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } + isSupported(returnType); try { - return eval( item, returnType); - } catch ( java.lang.NullPointerException npe ) { + return eval(item, returnType); + } catch (java.lang.NullPointerException npe) { // If VariableResolver returns null Or if we get // NullPointerException at this stage for some other reason // then we have to reurn XPathException - throw new XPathExpressionException ( npe ); - } catch ( javax.xml.transform.TransformerException te ) { + throw new XPathExpressionException (npe); + } catch (javax.xml.transform.TransformerException te) { Throwable nestedException = te.getException(); - if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) { + if (nestedException instanceof javax.xml.xpath.XPathFunctionException) { throw (javax.xml.xpath.XPathFunctionException)nestedException; } else { // For any other exceptions we need to throw - // XPathExpressionException ( as per spec ) - throw new XPathExpressionException( te); + // XPathExpressionException (as per spec) + throw new XPathExpressionException(te); } } - } - /** - *

Evaluate the compiled XPath expression in the specified context and - * return the result as a String.

- * - *

This method calls {@link #evaluate(Object item, QName returnType)} - * with a returnType of - * {@link XPathConstants#STRING}.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * - * @param item The starting context (node or node list, for example). - * - * @return The String that is the result of evaluating the - * expression and converting the result to a - * String. - * - * @throws XPathExpressionException If the expression cannot be evaluated. - */ + + @Override public String evaluate(Object item) throws XPathExpressionException { - return (String)this.evaluate( item, XPathConstants.STRING ); + return (String)this.evaluate(item, XPathConstants.STRING); } - - - static DocumentBuilderFactory dbf = null; - static DocumentBuilder db = null; - static Document d = null; - - /** - *

Evaluate the compiled XPath expression in the context of the - * specified InputSource and return the result as the - * specified type.

- * - *

This method builds a data model for the {@link InputSource} and calls - * {@link #evaluate(Object item, QName returnType)} on the resulting - * document object.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If returnType is not one of the types defined in - * {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

- * - *

If source or returnType is null, - * then a NullPointerException is thrown.

- * - * @param source The InputSource of the document to evaluate - * over. - * @param returnType The desired return type. - * - * @return The Object that is the result of evaluating the - * expression and converting the result to - * returnType. - * - * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one - * of the types defined in {@link XPathConstants}. - * @throws NullPointerException If source or - * returnType is null. - */ + @Override public Object evaluate(InputSource source, QName returnType) throws XPathExpressionException { - if ( ( source == null ) || ( returnType == null ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_SOURCE_RETURN_TYPE_CANNOT_BE_NULL, - null ); - throw new NullPointerException ( fmsg ); - } - // Checking if requested returnType is supported. returnType need to be - // defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } + isSupported (returnType); try { - if ( dbf == null ) { - dbf = FactoryImpl.getDOMFactory(useServicesMechanism); - dbf.setNamespaceAware( true ); - dbf.setValidating( false ); - } - db = dbf.newDocumentBuilder(); - Document document = db.parse( source ); - return eval( document, returnType ); - } catch ( Exception e ) { - throw new XPathExpressionException ( e ); + Document document = getDocument(source); + return eval(document, returnType); + } catch (TransformerException e) { + throw new XPathExpressionException(e); } } - /** - *

Evaluate the compiled XPath expression in the context of the specified InputSource and return the result as a - * String.

- * - *

This method calls {@link #evaluate(InputSource source, QName returnType)} with a returnType of - * {@link XPathConstants#STRING}.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If source is null, then a NullPointerException is thrown.

- * - * @param source The InputSource of the document to evaluate over. - * - * @return The String that is the result of evaluating the expression and converting the result to a - * String. - * - * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws NullPointerException If source is null. - */ + @Override public String evaluate(InputSource source) throws XPathExpressionException { - return (String)this.evaluate( source, XPathConstants.STRING ); + return (String)this.evaluate(source, XPathConstants.STRING); } - private boolean isSupported( QName returnType ) { - // XPathConstants.STRING - if ( ( returnType.equals( XPathConstants.STRING ) ) || - ( returnType.equals( XPathConstants.NUMBER ) ) || - ( returnType.equals( XPathConstants.BOOLEAN ) ) || - ( returnType.equals( XPathConstants.NODE ) ) || - ( returnType.equals( XPathConstants.NODESET ) ) ) { + @Override + public T evaluateExpression(Object item, Class type) + throws XPathExpressionException { + isSupportedClassType(type); - return true; - } - return false; - } + try { + XObject resultObject = eval(item, xpath); + if (type.isAssignableFrom(XPathEvaluationResult.class)) { + return getXPathResult(resultObject, type); + } else { + return XPathResultImpl.getValue(resultObject, type); + } - private Object getResultAsType( XObject resultObject, QName returnType ) - throws javax.xml.transform.TransformerException { - // XPathConstants.STRING - if ( returnType.equals( XPathConstants.STRING ) ) { - return resultObject.str(); + } catch (javax.xml.transform.TransformerException te) { + throw new XPathExpressionException(te); } - // XPathConstants.NUMBER - if ( returnType.equals( XPathConstants.NUMBER ) ) { - return new Double ( resultObject.num()); - } - // XPathConstants.BOOLEAN - if ( returnType.equals( XPathConstants.BOOLEAN ) ) { - return new Boolean( resultObject.bool()); - } - // XPathConstants.NODESET ---ORdered, UNOrdered??? - if ( returnType.equals( XPathConstants.NODESET ) ) { - return resultObject.nodelist(); - } - // XPathConstants.NODE - if ( returnType.equals( XPathConstants.NODE ) ) { - NodeIterator ni = resultObject.nodeset(); - //Return the first node, or null - return ni.nextNode(); - } - // If isSupported check is already done then the execution path - // shouldn't come here. Being defensive - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString()}); - throw new IllegalArgumentException ( fmsg ); } + @Override + public XPathEvaluationResult evaluateExpression(Object item) + throws XPathExpressionException { + return evaluateExpression(item, XPathEvaluationResult.class); + } + + @Override + public T evaluateExpression(InputSource source, Class type) + throws XPathExpressionException { + Document document = getDocument(source); + return evaluateExpression(document, type); + } + + @Override + public XPathEvaluationResult evaluateExpression(InputSource source) + throws XPathExpressionException { + return evaluateExpression(source, XPathEvaluationResult.class); + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java index ebd6b2c712f..1bbfef442ad 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 1999-2004 The Apache Software Foundation. @@ -28,55 +27,37 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFunctionResolver; import javax.xml.xpath.XPathVariableResolver; import javax.xml.xpath.XPathExpression; - -import com.sun.org.apache.xml.internal.dtm.DTM; import com.sun.org.apache.xpath.internal.*; import com.sun.org.apache.xpath.internal.objects.XObject; -import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; -import com.sun.org.apache.xalan.internal.res.XSLMessages; -import com.sun.org.apache.xalan.internal.utils.FactoryImpl; import com.sun.org.apache.xalan.internal.utils.FeatureManager; - -import org.w3c.dom.Node; import org.w3c.dom.Document; -import org.w3c.dom.traversal.NodeIterator; - import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import javax.xml.parsers.*; - -import java.io.IOException; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathEvaluationResult; /** * The XPathImpl class provides implementation for the methods defined in - * javax.xml.xpath.XPath interface. This provide simple access to the results + * javax.xml.xpath.XPath interface. This provides simple access to the results * of an XPath expression. * - * * @author Ramesh Mandava + * + * Updated 12/04/2014: + * New methods: evaluateExpression + * Refactored to share code with XPathExpressionImpl. */ -public class XPathImpl implements javax.xml.xpath.XPath { +public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath { // Private variables - private XPathVariableResolver variableResolver; - private XPathFunctionResolver functionResolver; private XPathVariableResolver origVariableResolver; private XPathFunctionResolver origFunctionResolver; private NamespaceContext namespaceContext=null; - private JAXPPrefixResolver prefixResolver; - // By default Extension Functions are allowed in XPath Expressions. If - // Secure Processing Feature is set on XPathFactory then the invocation of - // extensions function need to throw XPathFunctionException - private boolean featureSecureProcessing = false; - private boolean useServiceMechanism = true; - private final FeatureManager featureManager; - XPathImpl( XPathVariableResolver vr, XPathFunctionResolver fr ) { + XPathImpl(XPathVariableResolver vr, XPathFunctionResolver fr) { this(vr, fr, false, true, new FeatureManager()); } - XPathImpl( XPathVariableResolver vr, XPathFunctionResolver fr, + XPathImpl(XPathVariableResolver vr, XPathFunctionResolver fr, boolean featureSecureProcessing, boolean useServiceMechanism, FeatureManager featureManager) { this.origVariableResolver = this.variableResolver = vr; @@ -86,451 +67,173 @@ public class XPathImpl implements javax.xml.xpath.XPath { this.featureManager = featureManager; } - /** - *

Establishes a variable resolver.

- * - * @param resolver Variable Resolver - */ + + //-Override- public void setXPathVariableResolver(XPathVariableResolver resolver) { - if ( resolver == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPathVariableResolver"} ); - throw new NullPointerException( fmsg ); - } + requireNonNull(resolver, "XPathVariableResolver"); this.variableResolver = resolver; } - /** - *

Returns the current variable resolver.

- * - * @return Current variable resolver - */ + //-Override- public XPathVariableResolver getXPathVariableResolver() { return variableResolver; } - /** - *

Establishes a function resolver.

- * - * @param resolver XPath function resolver - */ + //-Override- public void setXPathFunctionResolver(XPathFunctionResolver resolver) { - if ( resolver == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPathFunctionResolver"} ); - throw new NullPointerException( fmsg ); - } + requireNonNull(resolver, "XPathFunctionResolver"); this.functionResolver = resolver; } - /** - *

Returns the current function resolver.

- * - * @return Current function resolver - */ + //-Override- public XPathFunctionResolver getXPathFunctionResolver() { return functionResolver; } - /** - *

Establishes a namespace context.

- * - * @param nsContext Namespace context to use - */ + //-Override- public void setNamespaceContext(NamespaceContext nsContext) { - if ( nsContext == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"NamespaceContext"} ); - throw new NullPointerException( fmsg ); - } + requireNonNull(nsContext, "NamespaceContext"); this.namespaceContext = nsContext; - this.prefixResolver = new JAXPPrefixResolver ( nsContext ); + this.prefixResolver = new JAXPPrefixResolver (nsContext); } - /** - *

Returns the current namespace context.

- * - * @return Current Namespace context - */ + //-Override- public NamespaceContext getNamespaceContext() { return namespaceContext; } - private static Document d = null; - - private DocumentBuilder getParser() { - try { - // we'd really like to cache those DocumentBuilders, but we can't because: - // 1. thread safety. parsers are not thread-safe, so at least - // we need one instance per a thread. - // 2. parsers are non-reentrant, so now we are looking at having a - // pool of parsers. - // 3. then the class loading issue. The look-up procedure of - // DocumentBuilderFactory.newInstance() depends on context class loader - // and system properties, which may change during the execution of JVM. - // - // so we really have to create a fresh DocumentBuilder every time we need one - // - KK - DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(useServiceMechanism); - dbf.setNamespaceAware( true ); - dbf.setValidating( false ); - return dbf.newDocumentBuilder(); - } catch (ParserConfigurationException e) { - // this should never happen with a well-behaving JAXP implementation. - throw new Error(e); - } - } - - - private XObject eval(String expression, Object contextItem) - throws javax.xml.transform.TransformerException { - com.sun.org.apache.xpath.internal.XPath xpath = new com.sun.org.apache.xpath.internal.XPath( expression, - null, prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT ); - com.sun.org.apache.xpath.internal.XPathContext xpathSupport = null; - if ( functionResolver != null ) { - JAXPExtensionsProvider jep = new JAXPExtensionsProvider( - functionResolver, featureSecureProcessing, featureManager ); - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext( jep ); - } else { - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); - } - - XObject xobj = null; - - xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); - - // If item is null, then we will create a a Dummy contextNode - if ( contextItem instanceof Node ) { - xobj = xpath.execute (xpathSupport, (Node)contextItem, - prefixResolver ); - } else { - xobj = xpath.execute ( xpathSupport, DTM.NULL, prefixResolver ); - } - - return xobj; - } - /** - *

Evaluate an XPath expression in the specified context and return the result as the specified type.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If returnType is not one of the types defined in {@link XPathConstants} ( - * {@link XPathConstants#NUMBER NUMBER}, - * {@link XPathConstants#STRING STRING}, - * {@link XPathConstants#BOOLEAN BOOLEAN}, - * {@link XPathConstants#NODE NODE} or - * {@link XPathConstants#NODESET NODESET}) - * then an IllegalArgumentException is thrown.

- * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If expression or returnType is null, then a - * NullPointerException is thrown.

- * + * Evaluate an {@code XPath} expression in the specified context. * @param expression The XPath expression. - * @param item The starting context (node or node list, for example). - * @param returnType The desired return type. - * - * @return Result of evaluating an XPath expression as an Object of returnType. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If expression or returnType is null. + * @param contextItem The starting context. + * @return an XObject as the result of evaluating the expression + * @throws TransformerException if evaluating fails */ + private XObject eval(String expression, Object contextItem) + throws TransformerException { + requireNonNull(expression, "XPath expression"); + com.sun.org.apache.xpath.internal.XPath xpath = new com.sun.org.apache.xpath.internal.XPath(expression, + null, prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT); + + return eval(contextItem, xpath); + } + + //-Override- public Object evaluate(String expression, Object item, QName returnType) throws XPathExpressionException { - if ( expression == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPath expression"} ); - throw new NullPointerException ( fmsg ); - } - if ( returnType == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"returnType"} ); - throw new NullPointerException ( fmsg ); - } - // Checking if requested returnType is supported. returnType need to - // be defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } + //this check is necessary before calling eval to maintain binary compatibility + requireNonNull(expression, "XPath expression"); + isSupported(returnType); try { - XObject resultObject = eval( expression, item ); - return getResultAsType( resultObject, returnType ); - } catch ( java.lang.NullPointerException npe ) { + XObject resultObject = eval(expression, item); + return getResultAsType(resultObject, returnType); + } catch (java.lang.NullPointerException npe) { // If VariableResolver returns null Or if we get // NullPointerException at this stage for some other reason // then we have to reurn XPathException - throw new XPathExpressionException ( npe ); - } catch ( javax.xml.transform.TransformerException te ) { + throw new XPathExpressionException (npe); + } catch (TransformerException te) { Throwable nestedException = te.getException(); - if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) { + if (nestedException instanceof javax.xml.xpath.XPathFunctionException) { throw (javax.xml.xpath.XPathFunctionException)nestedException; } else { // For any other exceptions we need to throw - // XPathExpressionException ( as per spec ) - throw new XPathExpressionException ( te ); + // XPathExpressionException (as per spec) + throw new XPathExpressionException (te); } } } - private boolean isSupported( QName returnType ) { - if ( ( returnType.equals( XPathConstants.STRING ) ) || - ( returnType.equals( XPathConstants.NUMBER ) ) || - ( returnType.equals( XPathConstants.BOOLEAN ) ) || - ( returnType.equals( XPathConstants.NODE ) ) || - ( returnType.equals( XPathConstants.NODESET ) ) ) { - - return true; - } - return false; - } - - private Object getResultAsType( XObject resultObject, QName returnType ) - throws javax.xml.transform.TransformerException { - // XPathConstants.STRING - if ( returnType.equals( XPathConstants.STRING ) ) { - return resultObject.str(); - } - // XPathConstants.NUMBER - if ( returnType.equals( XPathConstants.NUMBER ) ) { - return new Double ( resultObject.num()); - } - // XPathConstants.BOOLEAN - if ( returnType.equals( XPathConstants.BOOLEAN ) ) { - return new Boolean( resultObject.bool()); - } - // XPathConstants.NODESET ---ORdered, UNOrdered??? - if ( returnType.equals( XPathConstants.NODESET ) ) { - return resultObject.nodelist(); - } - // XPathConstants.NODE - if ( returnType.equals( XPathConstants.NODE ) ) { - NodeIterator ni = resultObject.nodeset(); - //Return the first node, or null - return ni.nextNode(); - } - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString()}); - throw new IllegalArgumentException( fmsg ); - } - - - - /** - *

Evaluate an XPath expression in the specified context and return the result as a String.

- * - *

This method calls {@link #evaluate(String expression, Object item, QName returnType)} with a returnType of - * {@link XPathConstants#STRING}.

- * - *

See "Evaluation of XPath Expressions" of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If expression is null, then a NullPointerException is thrown.

- * - * @param expression The XPath expression. - * @param item The starting context (node or node list, for example). - * - * @return The String that is the result of evaluating the expression and - * converting the result to a String. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws NullPointerException If expression is null. - */ + //-Override- public String evaluate(String expression, Object item) throws XPathExpressionException { - return (String)this.evaluate( expression, item, XPathConstants.STRING ); + return (String)this.evaluate(expression, item, XPathConstants.STRING); } - /** - *

Compile an XPath expression for later evaluation.

- * - *

If expression contains any {@link XPathFunction}s, - * they must be available via the {@link XPathFunctionResolver}. - * An {@link XPathExpressionException} will be thrown if the XPathFunction - * cannot be resovled with the XPathFunctionResolver.

- * - *

If expression is null, a NullPointerException is thrown.

- * - * @param expression The XPath expression. - * - * @return Compiled XPath expression. - - * @throws XPathExpressionException If expression cannot be compiled. - * @throws NullPointerException If expression is null. - */ + //-Override- public XPathExpression compile(String expression) throws XPathExpressionException { - if ( expression == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPath expression"} ); - throw new NullPointerException ( fmsg ); - } + requireNonNull(expression, "XPath expression"); try { com.sun.org.apache.xpath.internal.XPath xpath = new XPath (expression, null, - prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT ); + prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT); // Can have errorListener XPathExpressionImpl ximpl = new XPathExpressionImpl (xpath, prefixResolver, functionResolver, variableResolver, - featureSecureProcessing, useServiceMechanism, featureManager ); + featureSecureProcessing, useServiceMechanism, featureManager); return ximpl; - } catch ( javax.xml.transform.TransformerException te ) { - throw new XPathExpressionException ( te ) ; + } catch (TransformerException te) { + throw new XPathExpressionException (te) ; } } - - /** - *

Evaluate an XPath expression in the context of the specified InputSource - * and return the result as the specified type.

- * - *

This method builds a data model for the {@link InputSource} and calls - * {@link #evaluate(String expression, Object item, QName returnType)} on the resulting document object.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If returnType is not one of the types defined in {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

- * - *

If expression, source or returnType is null, - * then a NullPointerException is thrown.

- * - * @param expression The XPath expression. - * @param source The input source of the document to evaluate over. - * @param returnType The desired return type. - * - * @return The Object that encapsulates the result of evaluating the expression. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If expression, source or returnType - * is null. - */ + //-Override- public Object evaluate(String expression, InputSource source, QName returnType) throws XPathExpressionException { - // Checking validity of different parameters - if( source== null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"source"} ); - throw new NullPointerException ( fmsg ); - } - if ( expression == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPath expression"} ); - throw new NullPointerException ( fmsg ); - } - if ( returnType == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"returnType"} ); - throw new NullPointerException ( fmsg ); - } - - //Checking if requested returnType is supported. - //returnType need to be defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } + isSupported(returnType); try { - - Document document = getParser().parse( source ); - - XObject resultObject = eval( expression, document ); - return getResultAsType( resultObject, returnType ); - } catch ( SAXException e ) { - throw new XPathExpressionException ( e ); - } catch( IOException e ) { - throw new XPathExpressionException ( e ); - } catch ( javax.xml.transform.TransformerException te ) { + Document document = getDocument(source); + XObject resultObject = eval(expression, document); + return getResultAsType(resultObject, returnType); + } catch (TransformerException te) { Throwable nestedException = te.getException(); - if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) { + if (nestedException instanceof javax.xml.xpath.XPathFunctionException) { throw (javax.xml.xpath.XPathFunctionException)nestedException; } else { - throw new XPathExpressionException ( te ); + throw new XPathExpressionException (te); } } - } - - - - /** - *

Evaluate an XPath expression in the context of the specified InputSource - * and return the result as a String.

- * - *

This method calls {@link #evaluate(String expression, InputSource source, QName returnType)} with a - * returnType of {@link XPathConstants#STRING}.

- * - *

See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If expression or source is null, - * then a NullPointerException is thrown.

- * - * @param expression The XPath expression. - * @param source The InputSource of the document to evaluate over. - * - * @return The String that is the result of evaluating the expression and - * converting the result to a String. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws NullPointerException If expression or source is null. - */ + //-Override- public String evaluate(String expression, InputSource source) throws XPathExpressionException { - return (String)this.evaluate( expression, source, XPathConstants.STRING ); + return (String)this.evaluate(expression, source, XPathConstants.STRING); } - /** - *

Reset this XPath to its original configuration.

- * - *

XPath is reset to the same state as when it was created with - * {@link XPathFactory#newXPath()}. - * reset() is designed to allow the reuse of existing XPaths - * thus saving resources associated with the creation of new XPaths.

- * - *

The reset XPath is not guaranteed to have the same - * {@link XPathFunctionResolver}, {@link XPathVariableResolver} - * or {@link NamespaceContext} Objects, e.g. {@link Object#equals(Object obj)}. - * It is guaranteed to have a functionally equal XPathFunctionResolver, - * XPathVariableResolver - * and NamespaceContext.

- */ + //-Override- public void reset() { this.variableResolver = this.origVariableResolver; this.functionResolver = this.origFunctionResolver; this.namespaceContext = null; } + //-Override- + public T evaluateExpression(String expression, Object item, Class type) + throws XPathExpressionException { + isSupportedClassType(type); + try { + XObject resultObject = eval(expression, item); + if (type.isAssignableFrom(XPathEvaluationResult.class)) { + return getXPathResult(resultObject, type); + } else { + return XPathResultImpl.getValue(resultObject, type); + } + } catch (TransformerException te) { + throw new XPathExpressionException (te); + } + } + + //-Override- + public XPathEvaluationResult evaluateExpression(String expression, Object item) + throws XPathExpressionException { + return evaluateExpression(expression, item, XPathEvaluationResult.class); + } + + //-Override- + public T evaluateExpression(String expression, InputSource source, Class type) + throws XPathExpressionException { + Document document = getDocument(source); + return evaluateExpression(expression, document, type); + } + + //-Override- + public XPathEvaluationResult evaluateExpression(String expression, InputSource source) + throws XPathExpressionException { + return evaluateExpression(expression, source, XPathEvaluationResult.class); + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java new file mode 100644 index 00000000000..da4cdfc6f25 --- /dev/null +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.org.apache.xpath.internal.jaxp; + +import com.sun.org.apache.xalan.internal.res.XSLMessages; +import com.sun.org.apache.xalan.internal.utils.FactoryImpl; +import com.sun.org.apache.xalan.internal.utils.FeatureManager; +import com.sun.org.apache.xml.internal.dtm.DTM; +import com.sun.org.apache.xpath.internal.objects.XObject; +import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; +import java.io.IOException; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathEvaluationResult; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFunctionResolver; +import javax.xml.xpath.XPathNodes; +import javax.xml.xpath.XPathVariableResolver; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeIterator; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * This class contains several utility methods used by XPathImpl and + * XPathExpressionImpl + */ +class XPathImplUtil { + XPathFunctionResolver functionResolver; + XPathVariableResolver variableResolver; + JAXPPrefixResolver prefixResolver; + boolean useServiceMechanism = true; + // By default Extension Functions are allowed in XPath Expressions. If + // Secure Processing Feature is set on XPathFactory then the invocation of + // extensions function need to throw XPathFunctionException + boolean featureSecureProcessing = false; + FeatureManager featureManager; + + /** + * Evaluate an XPath context using the internal XPath engine + * @param contextItem The XPath context + * @param xpath The internal XPath engine + * @return an XObject + * @throws javax.xml.transform.TransformerException If the expression cannot be evaluated. + */ + XObject eval(Object contextItem, com.sun.org.apache.xpath.internal.XPath xpath) + throws javax.xml.transform.TransformerException { + com.sun.org.apache.xpath.internal.XPathContext xpathSupport; + if (functionResolver != null) { + JAXPExtensionsProvider jep = new JAXPExtensionsProvider( + functionResolver, featureSecureProcessing, featureManager); + xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(jep); + } else { + xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); + } + + xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); + XObject xobj; + + Node contextNode = (Node)contextItem; + // We always need to have a ContextNode with Xalan XPath implementation + // To allow simple expression evaluation like 1+1 we are setting + // dummy Document as Context Node + if (contextNode == null) { + xobj = xpath.execute(xpathSupport, DTM.NULL, prefixResolver); + } else { + xobj = xpath.execute(xpathSupport, contextNode, prefixResolver); + } + + return xobj; + } + + /** + * Parse the input source and return a Document. + * @param source The {@code InputSource} of the document + * @return a DOM Document + * @throws XPathExpressionException if there is an error parsing the source. + */ + Document getDocument(InputSource source) + throws XPathExpressionException { + requireNonNull(source, "Source"); + try { + // we'd really like to cache those DocumentBuilders, but we can't because: + // 1. thread safety. parsers are not thread-safe, so at least + // we need one instance per a thread. + // 2. parsers are non-reentrant, so now we are looking at having a + // pool of parsers. + // 3. then the class loading issue. The look-up procedure of + // DocumentBuilderFactory.newInstance() depends on context class loader + // and system properties, which may change during the execution of JVM. + // + // so we really have to create a fresh DocumentBuilder every time we need one + // - KK + DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(useServiceMechanism); + dbf.setNamespaceAware(true); + dbf.setValidating(false); + return dbf.newDocumentBuilder().parse(source); + } catch (ParserConfigurationException | SAXException | IOException e) { + throw new XPathExpressionException (e); + } + } + + /** + * Get result depending on the QName type defined in XPathConstants + * @param resultObject the result of an evaluation + * @param returnType the return type + * @return result per the return type + * @throws TransformerException if the result can not be converted to + * the specified return type. + */ + Object getResultAsType(XObject resultObject, QName returnType) + throws TransformerException { + // XPathConstants.STRING + if (returnType.equals(XPathConstants.STRING)) { + return resultObject.str(); + } + // XPathConstants.NUMBER + if (returnType.equals(XPathConstants.NUMBER)) { + return resultObject.num(); + } + // XPathConstants.BOOLEAN + if (returnType.equals(XPathConstants.BOOLEAN)) { + return resultObject.bool(); + } + // XPathConstants.NODESET ---ORdered, UNOrdered??? + if (returnType.equals(XPathConstants.NODESET)) { + return resultObject.nodelist(); + } + // XPathConstants.NODE + if (returnType.equals(XPathConstants.NODE)) { + NodeIterator ni = resultObject.nodeset(); + //Return the first node, or null + return ni.nextNode(); + } + // If isSupported check is already done then the execution path + // shouldn't come here. Being defensive + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, + new Object[] { returnType.toString()}); + throw new IllegalArgumentException (fmsg); + } + + /** + * Construct an XPathExpressionResult object based on the result of the + * evaluation and cast to the specified class type. + * @param The class type + * @param resultObject the result of an evaluation + * @param type The class type expected to be returned by the XPath expression. + * @return an instance of the specified type or null if the XObject returned + * an UNKNOWN object type. + * @throws TransformerException if there is an error converting the result + * to the specified type. It's unlikely to happen. This is mostly needed + * by the internal XPath engine. + */ + T getXPathResult(XObject resultObject, Class type) + throws TransformerException { + int resultType = resultObject.getType(); + + switch (resultType) { + case XObject.CLASS_BOOLEAN : + return type.cast(new XPathResultImpl<>(resultObject, Boolean.class)); + case XObject.CLASS_NUMBER : + return type.cast(new XPathResultImpl<>(resultObject, Double.class)); + case XObject.CLASS_STRING : + return type.cast(new XPathResultImpl<>(resultObject, String.class)); + case XObject.CLASS_NODESET : + return type.cast(new XPathResultImpl<>(resultObject, XPathNodes.class)); + case XObject.CLASS_RTREEFRAG : //NODE + return type.cast(new XPathResultImpl<>(resultObject, Node.class)); + } + + return null; + } + + /** + * Check whether or not the specified type is supported + * @param The class type + * @param type The type to be checked + * @throws IllegalArgumentException if the type is not supported + */ + void isSupportedClassType(Class type) { + requireNonNull(type, "The class type"); + if (type.isAssignableFrom(Boolean.class) || + type.isAssignableFrom(Double.class) || + type.isAssignableFrom(Integer.class) || + type.isAssignableFrom(Long.class) || + type.isAssignableFrom(String.class) || + type.isAssignableFrom(XPathNodes.class) || + type.isAssignableFrom(Node.class) || + type.isAssignableFrom(XPathEvaluationResult.class)) { + return; + } + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, + new Object[] { type.toString() }); + throw new IllegalArgumentException (fmsg); + } + + /** + * Check if the requested returnType is supported. + * @param returnType the return type + * @throws IllegalArgumentException if the return type is not supported + */ + void isSupported(QName returnType) { + requireNonNull(returnType, "returnType"); + if (returnType.equals(XPathConstants.STRING) || + returnType.equals(XPathConstants.NUMBER) || + returnType.equals(XPathConstants.BOOLEAN) || + returnType.equals(XPathConstants.NODE) || + returnType.equals(XPathConstants.NODESET)) { + return; + } + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, + new Object[] { returnType.toString() }); + throw new IllegalArgumentException (fmsg); + } + + /** + * Checks that the specified parameter is not {@code null}. + * + * @param the type of the reference + * @param param the parameter to check for nullity + * @param paramName the parameter name + * @throws NullPointerException if {@code param} is {@code null} + */ + void requireNonNull(T param, String paramName) { + if (param == null) { + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, + new Object[] {paramName}); + throw new NullPointerException (fmsg); + } + } +} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java new file mode 100644 index 00000000000..14c291fc94d --- /dev/null +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.org.apache.xpath.internal.jaxp; + +import java.util.Iterator; +import javax.xml.xpath.XPathException; +import javax.xml.xpath.XPathNodes; +import javax.xml.xpath.XPathEvaluationResult.XPathResultType; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * This class implements XPathNodes that represents a set of nodes selected by + * evaluating an expression. + */ +public class XPathNodesImpl implements XPathNodes { + Class elementType; + NodeList nodeList = null; + + public XPathNodesImpl(NodeList nodeList, Class elementType) { + this.nodeList = nodeList; + this.elementType = elementType; + } + + @Override + public Iterator iterator() { + return new NodeSetIterator<>(elementType); + } + + class NodeSetIterator implements Iterator { + int currentIndex; + Class elementType; + NodeSetIterator(Class elementType) { + this.elementType = elementType; + } + public boolean hasNext() { + if (nodeList != null) { + return currentIndex < nodeList.getLength(); + } + + return false; + } + + public E next() { + if (nodeList != null && nodeList.getLength() > 0) { + return elementType.cast(nodeList.item(currentIndex++)); + } + return null; + } + } + + @Override + public int size() { + if (nodeList != null) { + return nodeList.getLength(); + } + return 0; + } + + @Override + public Node get(int index) throws XPathException { + if (index <0 || index >= size()) { + throw new IndexOutOfBoundsException("Index " + index + " is out of bounds"); + } + if (nodeList != null) { + return nodeList.item(index); + } + return null; + } +} diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathResultImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathResultImpl.java new file mode 100644 index 00000000000..4953702f4ba --- /dev/null +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathResultImpl.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.org.apache.xpath.internal.jaxp; + +import com.sun.org.apache.xpath.internal.objects.XObject; +import java.util.Objects; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathNodes; +import javax.xml.xpath.XPathEvaluationResult; +import javax.xml.xpath.XPathEvaluationResult.XPathResultType; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.traversal.NodeIterator; + + +/** + * This is the implementation of XPathEvaluationResult that represents the + * result of the evaluation of an XPath expression within the context of a + * particular node. + */ +class XPathResultImpl implements XPathEvaluationResult { + + XObject resultObject; + int resultType; + Class type; + XPathResultType mapToType; + NodeList nodeList = null; + int currentIndex; + Node currentNode; + + boolean boolValue = false; + Node node = null; + double numValue; + String strValue; + + /** + * Construct an XPathEvaluationResult object. + * + * @param resultObject internal XPath result object + * @param type class type + * @throws TransformerException if there is an error reading the XPath + * result. + */ + public XPathResultImpl(XObject resultObject, Class type) + throws TransformerException { + this.resultObject = resultObject; + resultType = resultObject.getType(); + this.type = type; + getResult(resultObject); + } + + /** + * Return the result type as an enum specified by {@code XPathResultType} + * @return the result type + */ + @Override + public XPathResultType type() { + return mapToType; + } + + /** + * Returns the value of the result as the type <T> specified for the class. + * + * @return The value of the result. + */ + @Override + public T value() { + Objects.requireNonNull(type); + try { + return getValue(resultObject, type); + } catch (TransformerException ex) { + throw new RuntimeException(ex); + } + } + + /** + * Read the XObject and set values in accordance with the result type + * @param resultObject internal XPath result object + * @throws TransformerException if there is an error reading the XPath + * result. + */ + private void getResult(XObject resultObject) throws TransformerException { + switch (resultType) { + case XObject.CLASS_BOOLEAN: + boolValue = resultObject.bool(); + mapToType = XPathResultType.BOOLEAN; + break; + case XObject.CLASS_NUMBER: + numValue = resultObject.num(); + mapToType = XPathResultType.NUMBER; + break; + case XObject.CLASS_STRING: + strValue = resultObject.str(); + mapToType = XPathResultType.STRING; + break; + case XObject.CLASS_NODESET: + mapToType = XPathResultType.NODESET; + nodeList = resultObject.nodelist(); + break; + case XObject.CLASS_RTREEFRAG: //NODE + mapToType = XPathResultType.NODE; + NodeIterator ni = resultObject.nodeset(); + //Return the first node, or null + node = ni.nextNode(); + break; + } + } + + /** + * Read the internal result object and return the value in accordance with + * the type specified. + * + * @param The expected class type. + * @param resultObject internal XPath result object + * @param type the class type + * @return The value of the result, null in case of unexpected type. + * @throws TransformerException if there is an error reading the XPath + * result. + */ + static T getValue(XObject resultObject, Class type) throws TransformerException { + Objects.requireNonNull(type); + if (type.isAssignableFrom(XPathEvaluationResult.class)) { + return type.cast(new XPathResultImpl(resultObject, type)); + } + int resultType = classToInternalType(type); + switch (resultType) { + case XObject.CLASS_BOOLEAN: + return type.cast(resultObject.bool()); + case XObject.CLASS_NUMBER: + if (Double.class.isAssignableFrom(type)) { + return type.cast(resultObject.num()); + } else if (Integer.class.isAssignableFrom(type)) { + return type.cast((int)resultObject.num()); + } else if (Long.class.isAssignableFrom(type)) { + return type.cast((long)resultObject.num()); + } + /* + This is to suppress warnings. By the current specification, + among numeric types, only Double, Integer and Long are supported. + */ + break; + case XObject.CLASS_STRING: + return type.cast(resultObject.str()); + case XObject.CLASS_NODESET: + XPathNodes nodeSet = new XPathNodesImpl(resultObject.nodelist(), + Node.class); + return type.cast(nodeSet); + case XObject.CLASS_RTREEFRAG: //NODE + NodeIterator ni = resultObject.nodeset(); + //Return the first node, or null + return type.cast(ni.nextNode()); + } + + return null; + } + + /** + * Map the specified class type to the internal result type + * + * @param The expected class type. + * @param type the class type + * @return the internal XObject type. + */ + static int classToInternalType(Class type) { + if (type.isAssignableFrom(Boolean.class)) { + return XObject.CLASS_BOOLEAN; + } else if (Number.class.isAssignableFrom(type)) { + return XObject.CLASS_NUMBER; + } else if (type.isAssignableFrom(String.class)) { + return XObject.CLASS_STRING; + } else if (type.isAssignableFrom(XPathNodes.class)) { + return XObject.CLASS_NODESET; + } else if (type.isAssignableFrom(Node.class)) { + return XObject.CLASS_RTREEFRAG; + } + return XObject.CLASS_NULL; + } +} diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java index 90ba4feac2a..6e77e23e441 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, 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 @@ -25,12 +25,12 @@ package javax.xml.xpath; -import org.xml.sax.InputSource; -import javax.xml.namespace.QName; import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import org.xml.sax.InputSource; /** - *

XPath provides access to the XPath evaluation environment and expressions.

+ * {@code XPath} provides access to the XPath evaluation environment and expressions. * * * @@ -39,7 +39,6 @@ import javax.xml.namespace.NamespaceContext; * * * - * * * * * * @@ -65,7 +64,7 @@ import javax.xml.namespace.NamespaceContext; * If the expression contains a function reference, the function will be found through the {@link XPathFunctionResolver} * set with {@link #setXPathFunctionResolver(XPathFunctionResolver resolver)}. * An {@link XPathExpressionException} is raised if the function resolver is undefined or - * the function resolver returns null for the function.

+ * the function resolver returns {@code null} for the function. * * * @@ -80,7 +79,7 @@ import javax.xml.namespace.NamespaceContext; * * *
Evaluation of XPath Expressions.
context @@ -55,8 +54,8 @@ import javax.xml.namespace.NamespaceContext; * If the expression contains a variable reference, its value will be found through the {@link XPathVariableResolver} * set with {@link #setXPathVariableResolver(XPathVariableResolver resolver)}. * An {@link XPathExpressionException} is raised if the variable resolver is undefined or - * the resolver returns null for the variable. - * The value of a variable must be immutable through the course of any single evaluation.

+ * the resolver returns {@code null} for the variable. + * The value of a variable must be immutable through the course of any single evaluation. *
* This result of evaluating an expression is converted to an instance of the desired return type. * Valid return types are defined in {@link XPathConstants}. - * Conversion to the return type follows XPath conversion rules.

+ * Conversion to the return type follows XPath conversion rules. *
@@ -88,9 +87,9 @@ import javax.xml.namespace.NamespaceContext; *

An XPath object is not thread-safe and not reentrant. * In other words, it is the application's responsibility to make * sure that one {@link XPath} object is not used from - * more than one thread at any given time, and while the evaluate + * more than one thread at any given time, and while the {@code evaluate} * method is invoked, applications may not recursively call - * the evaluate method. + * the {@code evaluate} method. *

* * @author Norman Walsh @@ -100,191 +99,189 @@ import javax.xml.namespace.NamespaceContext; */ public interface XPath { - /** - *

Reset this XPath to its original configuration.

- * - *

XPath is reset to the same state as when it was created with - * {@link XPathFactory#newXPath()}. - * reset() is designed to allow the reuse of existing XPaths - * thus saving resources associated with the creation of new XPaths.

- * - *

The reset XPath is not guaranteed to have the same {@link XPathFunctionResolver}, {@link XPathVariableResolver} - * or {@link NamespaceContext} Objects, e.g. {@link Object#equals(Object obj)}. - * It is guaranteed to have a functionally equal XPathFunctionResolver, XPathVariableResolver - * and NamespaceContext.

- */ - public void reset(); /** - *

Establish a variable resolver.

+ * Reset this {@code XPath} to its original configuration. * - *

A NullPointerException is thrown if resolver is null.

+ *

{@code XPath} is reset to the same state as when it was created with + * {@link XPathFactory#newXPath()}. + * {@code reset()} is designed to allow the reuse of existing {@code XPath}s + * thus saving resources associated with the creation of new {@code XPath}s. + * + *

The reset {@code XPath} is not guaranteed to have the same + * {@link XPathFunctionResolver}, {@link XPathVariableResolver} + * or {@link NamespaceContext} {@code Object}s, e.g. {@link Object#equals(Object obj)}. + * It is guaranteed to have a functionally equal {@code XPathFunctionResolver}, + * {@code XPathVariableResolver} and {@code NamespaceContext}. + */ + public void reset(); + + /** + * Establish a variable resolver. + * + *

A {@code NullPointerException} is thrown if {@code resolver} is {@code null}. * * @param resolver Variable resolver. * - * @throws NullPointerException If resolver is null. + * @throws NullPointerException If {@code resolver} is {@code null}. */ public void setXPathVariableResolver(XPathVariableResolver resolver); /** - *

Return the current variable resolver.

+ * Return the current variable resolver. * - *

null is returned in no variable resolver is in effect.

+ *

{@code null} is returned in no variable resolver is in effect. * * @return Current variable resolver. */ public XPathVariableResolver getXPathVariableResolver(); /** - *

Establish a function resolver.

+ * Establish a function resolver. * - *

A NullPointerException is thrown if resolver is null.

+ *

A {@code NullPointerException} is thrown if {@code resolver} is {@code null}. * * @param resolver XPath function resolver. * - * @throws NullPointerException If resolver is null. + * @throws NullPointerException If {@code resolver} is {@code null}. */ public void setXPathFunctionResolver(XPathFunctionResolver resolver); /** - *

Return the current function resolver.

- * - *

null is returned in no function resolver is in effect.

+ * Return the current function resolver. + *

+ * {@code null} is returned in no function resolver is in effect. * * @return Current function resolver. */ public XPathFunctionResolver getXPathFunctionResolver(); /** - *

Establish a namespace context.

+ * Establish a namespace context. * - *

A NullPointerException is thrown if nsContext is null.

+ *

A {@code NullPointerException} is thrown if {@code nsContext} is {@code null}. * * @param nsContext Namespace context to use. * - * @throws NullPointerException If nsContext is null. + * @throws NullPointerException If {@code nsContext} is {@code null}. */ public void setNamespaceContext(NamespaceContext nsContext); /** - *

Return the current namespace context.

+ * Return the current namespace context. * - *

null is returned in no namespace context is in effect.

+ *

{@code null} is returned in no namespace context is in effect. * * @return Current Namespace context. */ public NamespaceContext getNamespaceContext(); /** - *

Compile an XPath expression for later evaluation.

+ * Compile an XPath expression for later evaluation. * - *

If expression contains any {@link XPathFunction}s, + *

If {@code expression} contains any {@link XPathFunction}s, * they must be available via the {@link XPathFunctionResolver}. * An {@link XPathExpressionException} will be thrown if the - * XPathFunction - * cannot be resovled with the XPathFunctionResolver.

+ * {@code XPathFunction} + * cannot be resovled with the {@code XPathFunctionResolver}. * - *

If expression contains any variables, the + *

If {@code expression} contains any variables, the * {@link XPathVariableResolver} in effect - * at compile time will be used to resolve them.

- * - *

If expression is null, a NullPointerException is thrown.

+ * at compile time will be used to resolve them. * * @param expression The XPath expression. * * @return Compiled XPath expression. - * @throws XPathExpressionException If expression cannot be compiled. - * @throws NullPointerException If expression is null. + * @throws XPathExpressionException If {@code expression} cannot be compiled. + * @throws NullPointerException If {@code expression} is {@code null}. */ public XPathExpression compile(String expression) throws XPathExpressionException; /** - *

Evaluate an XPath expression in the specified context and return the result as the specified type.

+ * Evaluate an {@code XPath} expression in the specified context and + * return the result as the specified type. * - *

See Evaluation of XPath Expressions for context item evaluation, - * variable, function and QName resolution and return type conversion.

+ *

+ * See Evaluation of XPath Expressions + * for context item evaluation, variable, function and {@code QName} resolution + * and return type conversion. + *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. * - *

If returnType is not one of the types defined in {@link XPathConstants} ( + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @param expression The XPath expression. + * @param item The context the XPath expression will be evaluated in. + * @param returnType The result type expected to be returned by the XPath expression. + * + * @return The result of evaluating an XPath expression as an {@code Object} of {@code returnType}. + * + * @throws XPathExpressionException If {@code expression} cannot be evaluated. + * @throws IllegalArgumentException If {@code returnType} is not one of the types defined in {@link XPathConstants} ( * {@link XPathConstants#NUMBER NUMBER}, * {@link XPathConstants#STRING STRING}, * {@link XPathConstants#BOOLEAN BOOLEAN}, * {@link XPathConstants#NODE NODE} or - * {@link XPathConstants#NODESET NODESET}) - * then an IllegalArgumentException is thrown.

- * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If expression or returnType is null, then a - * NullPointerException is thrown.

- * - * @param expression The XPath expression. - * @param item The starting context (a node, for example). - * @param returnType The desired return type. - * - * @return Result of evaluating an XPath expression as an Object of returnType. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If expression or returnType is null. + * {@link XPathConstants#NODESET NODESET}). + * @throws NullPointerException If {@code expression or returnType} is {@code null}. */ public Object evaluate(String expression, Object item, QName returnType) throws XPathExpressionException; /** - *

Evaluate an XPath expression in the specified context and return the result as a String.

+ * Evaluate an XPath expression in the specified context and return the result as a {@code String}. * - *

This method calls {@link #evaluate(String expression, Object item, QName returnType)} with a returnType of - * {@link XPathConstants#STRING}.

+ *

This method calls {@link #evaluate(String expression, Object item, QName returnType)} with a {@code returnType} of + * {@link XPathConstants#STRING}. * *

See Evaluation of XPath Expressions for context item evaluation, - * variable, function and QName resolution and return type conversion.

+ * variable, function and QName resolution and return type conversion. * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If expression is null, then a NullPointerException is thrown.

+ *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. * * @param expression The XPath expression. - * @param item The starting context (a node, for example). + * @param item The context the XPath expression will be evaluated in. * - * @return The String that is the result of evaluating the expression and - * converting the result to a String. + * @return The result of evaluating an XPath expression as a {@code String}. * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws NullPointerException If expression is null. + * @throws XPathExpressionException If {@code expression} cannot be evaluated. + * @throws NullPointerException If {@code expression} is {@code null}. */ public String evaluate(String expression, Object item) throws XPathExpressionException; /** - *

Evaluate an XPath expression in the context of the specified InputSource - * and return the result as the specified type.

+ * Evaluate an XPath expression in the context of the specified {@code InputSource} + * and return the result as the specified type. * *

This method builds a data model for the {@link InputSource} and calls - * {@link #evaluate(String expression, Object item, QName returnType)} on the resulting document object.

+ * {@link #evaluate(String expression, Object item, QName returnType)} on the resulting document object. * *

See Evaluation of XPath Expressions for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If returnType is not one of the types defined in {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

- * - *

If expression, source or returnType is null, - * then a NullPointerException is thrown.

+ * variable, function and QName resolution and return type conversion. * * @param expression The XPath expression. * @param source The input source of the document to evaluate over. * @param returnType The desired return type. * - * @return The Object that encapsulates the result of evaluating the expression. + * @return The {@code Object} that encapsulates the result of evaluating the expression. * * @throws XPathExpressionException If expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If expression, source or returnType - * is null. + * @throws IllegalArgumentException If {@code returnType} is not one of the types defined in {@link XPathConstants}. + * @throws NullPointerException If {@code expression, source or returnType} is {@code null}. */ public Object evaluate( String expression, @@ -293,27 +290,209 @@ public interface XPath { throws XPathExpressionException; /** - *

Evaluate an XPath expression in the context of the specified InputSource - * and return the result as a String.

+ * Evaluate an XPath expression in the context of the specified {@code InputSource} + * and return the result as a {@code String}. * *

This method calls {@link #evaluate(String expression, InputSource source, QName returnType)} with a - * returnType of {@link XPathConstants#STRING}.

+ * {@code returnType} of {@link XPathConstants#STRING}. * *

See Evaluation of XPath Expressions for context item evaluation, - * variable, function and QName resolution and return type conversion.

- * - *

If expression or source is null, - * then a NullPointerException is thrown.

+ * variable, function and QName resolution and return type conversion. * * @param expression The XPath expression. - * @param source The InputSource of the document to evaluate over. + * @param source The {@code InputSource} of the document to evaluate over. * - * @return The String that is the result of evaluating the expression and - * converting the result to a String. + * @return The {@code String} that is the result of evaluating the expression and + * converting the result to a {@code String}. * * @throws XPathExpressionException If expression cannot be evaluated. - * @throws NullPointerException If expression or source is null. + * @throws NullPointerException If {@code expression or source} is {@code null}. */ public String evaluate(String expression, InputSource source) throws XPathExpressionException; + + /** + * Evaluate an XPath expression in the specified context and return + * the result with the type specified through the {@code class type} + * + *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+     *     (T)evaluate(expression, item,
+     *           XPathEvaluationResult.XPathResultType.getQNameType(type));
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type, specifying + * XPathEvaluationResult as the type will result in IllegalArgumentException. + * Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must override + * this method. + * + * @param The class type that will be returned by the XPath expression. + * @param expression The XPath expression. + * @param item The context the XPath expression will be evaluated in. + * @param type The class type expected to be returned by the XPath expression. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If {@code type} is not of the types + * corresponding to the types defined in the {@link XPathEvaluationResult.XPathResultType}, + * or XPathEvaluationResult is specified as the type but an implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type is not available. + * @throws NullPointerException If {@code expression or type} is {@code null}. + * + * @since 1.9 + */ + default T evaluateExpression(String expression, Object item, Class type) + throws XPathExpressionException { + return type.cast(evaluate(expression, item, + XPathEvaluationResult.XPathResultType.getQNameType(type))); + } + + /** + * Evaluate an XPath expression in the specified context. This is equivalent to + * calling {@link #evaluateExpression(String expression, Object item, Class type)} + * with type {@link XPathEvaluationResult}: + *
 {@code
+     *     evaluateExpression(expression, item, XPathEvaluationResult.class);
+     * }
+ *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+     *     evaluateExpression(expression, item, XPathEvaluationResult.class);
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} + * type, the default implementation of this method will always throw an + * IllegalArgumentException. Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must therefore + * override this method. + * + * @param expression The XPath expression. + * @param item The context the XPath expression will be evaluated in. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If the implementation of this method + * does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. + * @throws NullPointerException If {@code expression} is {@code null}. + * + * @since 1.9 + */ + default XPathEvaluationResult evaluateExpression(String expression, Object item) + throws XPathExpressionException + { + return evaluateExpression(expression, item, XPathEvaluationResult.class); + } + + /** + * Evaluate an XPath expression in the context of the specified {@code source} + * and return the result as specified. + *

+ * This method builds a data model for the {@link InputSource} and calls + * {@link #evaluateExpression(String expression, Object item, Class type)} + * on the resulting document object. The data model is usually + * {@link org.w3c.dom.Document} + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+           (T)evaluate(expression, source,
+                XPathEvaluationResult.XPathResultType.getQNameType(type));
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type, specifying + * XPathEvaluationResult as the type will result in IllegalArgumentException. + * Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must override + * this method. + * + * @param The class type that will be returned by the XPath expression. + * @param expression The XPath expression. + * @param source The input source of the document to evaluate over. + * @param type The class type expected to be returned by the XPath expression. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If {@code type} is not of the types + * corresponding to the types defined in the {@link XPathEvaluationResult.XPathResultType + * XPathResultType}, or XPathEvaluationResult is specified as the type but an + * implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type is not available. + * @throws NullPointerException If {@code expression, source or type}is {@code null}. + * + * @since 1.9 + */ + default T evaluateExpression(String expression, InputSource source, Class type) + throws XPathExpressionException + { + return type.cast(evaluate(expression, source, + XPathEvaluationResult.XPathResultType.getQNameType(type))); + } + + /** + * Evaluate an XPath expression in the specified context. This is equivalent to + * calling {@link #evaluateExpression(String expression, Object item, Class type)} + * with type {@link XPathEvaluationResult}: + *
 {@code
+     *     evaluateExpression(expression, item, XPathEvaluationResult.class);
+     * }
+ *

+ * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+     *     evaluateExpression(expression, source, XPathEvaluationResult.class);
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} + * type, the default implementation of this method will always throw an + * IllegalArgumentException. Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must therefore + * override this method. + * + * @param expression The XPath expression. + * @param source The input source of the document to evaluate over. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If the implementation of this method + * does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. + * @throws NullPointerException If {@code expression or source} is {@code null}. + * + * @since 1.9 + */ + default XPathEvaluationResult evaluateExpression(String expression, InputSource source) + throws XPathExpressionException + { + return evaluateExpression(expression, source, XPathEvaluationResult.class); + } } diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java new file mode 100644 index 00000000000..745473975e5 --- /dev/null +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javax.xml.xpath; + +import java.util.Objects; +import javax.xml.namespace.QName; +import org.w3c.dom.Node; +/** + * The {@code XPathEvaluationResult} interface represents the result of the + * evaluation of an XPath expression within the context of a particular node. + * The evaluation of an XPath expression can result in various result types as + * defined in XML Path Language (XPath) Version 1.0. + *

+ * + * @param the object type returned by the XPath evaluation. + * @see XML Path Language (XPath) Version + * 1.0 + * + * @since 1.9 + */ +public interface XPathEvaluationResult { + + /** + * XPathResultType represents possible return types of an XPath evaluation. + * Provided as an enum type, it allows the use of switch statement. At the + * same time, a mapping is provided between the original QName types in + * {@link XPathConstants} and class types used in the generic methods. + */ + public static enum XPathResultType { + /** + * Any type that represents any of the 5 other types listed below. + * Maps to {@link XPathEvaluationResult}. + */ + ANY(new QName("http://www.w3.org/1999/XSL/Transform", "any"), XPathEvaluationResult.class), + /** + * The XPath 1.0 boolean data type. Maps to Java {@link Boolean}. + */ + BOOLEAN(XPathConstants.BOOLEAN, Boolean.class), + /** + * The XPath 1.0 Number data type. Maps to Java {@link Number}. Of the + * subtypes of Number, only Double, Integer and Long are required. + */ + NUMBER(XPathConstants.NUMBER, Number.class), + /** + * The XPath 1.0 String data type. Maps to Java {@link String}. + */ + STRING(XPathConstants.STRING, String.class), + /** + * The XPath 1.0 NodeSet data type. Maps to {@link org.w3c.dom.NodeList}. + */ + NODESET(XPathConstants.NODESET, XPathNodes.class), + /** + * The XPath 1.0 NodeSet data type. Maps to {@link org.w3c.dom.Node}. + */ + NODE(XPathConstants.NODE, Node.class); + + final QName qnameType; + final Class clsType; + XPathResultType(QName qnameType, Class clsType) { + this.qnameType = qnameType; + this.clsType = clsType; + } + + /** + * Compares this type to the specified class type. + * @param clsType class type + * @return true if the argument is not null and is a class type that + * matches that this type represents, false otherwise. + */ + private boolean equalsClassType(Class clsType) { + Objects.nonNull(clsType); + if (clsType.isAssignableFrom(this.clsType)) { + return true; + } + return false; + } + + /** + * Returns the QName type as specified in {@link XPathConstants} that + * corresponds to the specified class type. + * @param clsType a class type that the enum type supports + * @return the QName type that matches with the specified class type, + * null if there is no match + */ + static public QName getQNameType(Class clsType) { + for (XPathResultType type : XPathResultType.values()) { + if (type.equalsClassType(clsType)) { + return type.qnameType; + } + } + return null; + } + } + + /** + * Return the result type as an enum specified by {@code XPathResultType} + * @return the result type + */ + public XPathResultType type(); + + /** + * Returns the value of the result as the type <T> specified for the class. + * + * @return The value of the result. + */ + public T value(); + +} diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java index 0f980f6ed8e..a7625ec1b87 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, 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 @@ -25,11 +25,11 @@ package javax.xml.xpath; -import org.xml.sax.InputSource; import javax.xml.namespace.QName; +import org.xml.sax.InputSource; /** - *

XPathExpression provides access to compiled XPath expressions.

+ *

{@code XPathExpression} provides access to compiled XPath expressions.

* * * @@ -53,7 +53,7 @@ import javax.xml.namespace.QName; * * @@ -62,7 +62,7 @@ import javax.xml.namespace.QName; * * * @@ -84,9 +84,9 @@ import javax.xml.namespace.QName; *

An XPath expression is not thread-safe and not reentrant. * In other words, it is the application's responsibility to make * sure that one {@link XPathExpression} object is not used from - * more than one thread at any given time, and while the evaluate + * more than one thread at any given time, and while the {@code evaluate} * method is invoked, applications may not recursively call - * the evaluate method. + * the {@code evaluate} method. *

* * @author Norman Walsh @@ -96,50 +96,56 @@ import javax.xml.namespace.QName; */ public interface XPathExpression { + /** *

Evaluate the compiled XPath expression in the specified context and return the result as the specified type.

* *

See Evaluation of XPath Expressions for context item evaluation, * variable, function and QName resolution and return type conversion.

* - *

If returnType is not one of the types defined in {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

+ *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. * - *

If a null value is provided for - * item, an empty document will be used for the - * context. - * If returnType is null, then a NullPointerException is thrown.

+ * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. * - * @param item The starting context (a node, for example). - * @param returnType The desired return type. + * @param item The context the XPath expression will be evaluated in. + * @param returnType The result type expected to be returned by the XPath expression. * - * @return The Object that is the result of evaluating the expression and converting the result to - * returnType. + * @return The {@code Object} that is the result of evaluating the expression and converting the result to + * {@code returnType}. * * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If returnType is null. + * @throws IllegalArgumentException If {@code returnType} is not one of the types defined in {@link XPathConstants}. + * @throws NullPointerException If {@code returnType} is {@code null}. */ public Object evaluate(Object item, QName returnType) throws XPathExpressionException; /** - *

Evaluate the compiled XPath expression in the specified context and return the result as a String.

+ *

Evaluate the compiled XPath expression in the specified context and return the result as a {@code String}.

* - *

This method calls {@link #evaluate(Object item, QName returnType)} with a returnType of + *

This method calls {@link #evaluate(Object item, QName returnType)} with a {@code returnType} of * {@link XPathConstants#STRING}.

* *

See Evaluation of XPath Expressions for context item evaluation, * variable, function and QName resolution and return type conversion.

* - *

If a null value is provided for - * item, an empty document will be used for the - * context. + *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. * - * @param item The starting context (a node, for example). + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. * - * @return The String that is the result of evaluating the expression and converting the result to a - * String. + * @param item The context the XPath expression will be evaluated in. + * + * @return The result of evaluating an XPath expression as a {@code String}. * * @throws XPathExpressionException If the expression cannot be evaluated. */ @@ -147,7 +153,7 @@ public interface XPathExpression { throws XPathExpressionException; /** - *

Evaluate the compiled XPath expression in the context of the specified InputSource and return the result as the + *

Evaluate the compiled XPath expression in the context of the specified {@code InputSource} and return the result as the * specified type.

* *

This method builds a data model for the {@link InputSource} and calls @@ -156,45 +162,225 @@ public interface XPathExpression { *

See Evaluation of XPath Expressions for context item evaluation, * variable, function and QName resolution and return type conversion.

* - *

If returnType is not one of the types defined in {@link XPathConstants}, - * then an IllegalArgumentException is thrown.

+ *

If {@code returnType} is not one of the types defined in {@link XPathConstants}, + * then an {@code IllegalArgumentException} is thrown.

* - *

If source or returnType is null, - * then a NullPointerException is thrown.

+ *

If {@code source} or {@code returnType} is {@code null}, + * then a {@code NullPointerException} is thrown.

* - * @param source The InputSource of the document to evaluate over. + * @param source The {@code InputSource} of the document to evaluate over. * @param returnType The desired return type. * - * @return The Object that is the result of evaluating the expression and converting the result to - * returnType. + * @return The {@code Object} that is the result of evaluating the expression and converting the result to + * {@code returnType}. * * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws IllegalArgumentException If returnType is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If source or returnType is null. + * @throws IllegalArgumentException If {@code returnType} is not one of the types defined in {@link XPathConstants}. + * @throws NullPointerException If {@code source or returnType} is {@code null}. */ public Object evaluate(InputSource source, QName returnType) throws XPathExpressionException; /** - *

Evaluate the compiled XPath expression in the context of the specified InputSource and return the result as a - * String.

+ *

Evaluate the compiled XPath expression in the context of the specified {@code InputSource} and return the result as a + * {@code String}.

* - *

This method calls {@link #evaluate(InputSource source, QName returnType)} with a returnType of + *

This method calls {@link #evaluate(InputSource source, QName returnType)} with a {@code returnType} of * {@link XPathConstants#STRING}.

* *

See Evaluation of XPath Expressions for context item evaluation, * variable, function and QName resolution and return type conversion.

* - *

If source is null, then a NullPointerException is thrown.

+ *

If {@code source} is {@code null}, then a {@code NullPointerException} is thrown.

* - * @param source The InputSource of the document to evaluate over. + * @param source The {@code InputSource} of the document to evaluate over. * - * @return The String that is the result of evaluating the expression and converting the result to a - * String. + * @return The {@code String} that is the result of evaluating the expression and converting the result to a + * {@code String}. * * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws NullPointerException If source is null. + * @throws NullPointerException If {@code source} is {@code null}. */ public String evaluate(InputSource source) throws XPathExpressionException; + + /** + * Evaluate the compiled XPath expression in the specified context, and return + * the result with the type specified through the {@code class type}. + * + *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+     *     (T)evaluate(item, XPathEvaluationResult.XPathResultType.getQNameType(type));
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type, specifying + * XPathEvaluationResult as the type will result in IllegalArgumentException. + * Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must override + * this method. + * + * @param The class type that will be returned by the XPath expression. + * @param item The context the XPath expression will be evaluated in. + * @param type The class type expected to be returned by the XPath expression. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If {@code type} is not of the types + * corresponding to the types defined in the {@link XPathEvaluationResult.XPathResultType + * XPathResultType}, or XPathEvaluationResult is specified as the type but an + * implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type is not available. + * @throws NullPointerException If {@code type} is {@code null}. + * + * @since 1.9 + */ + default T evaluateExpression(Object item, Class type) + throws XPathExpressionException + { + return type.cast(evaluate(item, XPathEvaluationResult.XPathResultType.getQNameType(type))); + } + + /** + * Evaluate the compiled XPath expression in the specified context. This is + * equivalent to calling {@link #evaluateExpression(Object item, Class type)} + * with type {@link XPathEvaluationResult}: + *
 {@code
+     *     evaluateExpression(item, XPathEvaluationResult.class);
+     * }
+ *

+ * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+     *     evaluateExpression(item, XPathEvaluationResult.class);
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} + * type, the default implementation of this method will always throw an + * IllegalArgumentException. Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must therefore + * override this method. + * + * @param item The context the XPath expression will be evaluated in. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If the implementation of this method + * does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. + * + * @since 1.9 + */ + default XPathEvaluationResult evaluateExpression(Object item) + throws XPathExpressionException + { + return evaluateExpression(item, XPathEvaluationResult.class); + } + + /** + * Evaluate the compiled XPath expression in the specified context, + * and return the result with the type specified through the {@code class type} + *

+ * This method builds a data model for the {@link InputSource} and calls + * {@link #evaluateExpression(Object item, Class type)} on the resulting + * document object. + *

+ * By default, the JDK's data model is {@link org.w3c.dom.Document}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+           (T)evaluate(source, XPathEvaluationResult.XPathResultType.getQNameType(type));
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type, specifying + * XPathEvaluationResult as the type will result in IllegalArgumentException. + * Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must override + * this method. + * + * @param The class type that will be returned by the XPath expression. + * @param source The {@code InputSource} of the document to evaluate over. + * @param type The class type expected to be returned by the XPath expression. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If {@code type} is not of the types + * corresponding to the types defined in the {@link XPathEvaluationResult.XPathResultType + * XPathResultType}, or XPathEvaluationResult is specified as the type but an + * implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type + * is not available. + * @throws NullPointerException If {@code source or type} is {@code null}. + * + * @since 1.9 + */ + default T evaluateExpression(InputSource source, Class type) + throws XPathExpressionException + { + return type.cast(evaluate(source, XPathEvaluationResult.XPathResultType.getQNameType(type))); + } + + /** + * Evaluate the compiled XPath expression in the specified context. This is + * equivalent to calling {@link #evaluateExpression(InputSource source, Class type)} + * with type {@link XPathEvaluationResult}: + *
 {@code
+     *     evaluateExpression(source, XPathEvaluationResult.class);
+     * }
+ *

+ * + * @implSpec + * The default implementation in the XPath API is equivalent to: + *

 {@code
+     *     (XPathEvaluationResult)evaluateExpression(source, XPathEvaluationResult.class);
+     * }
+ * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} + * type, the default implementation of this method will always throw an + * IllegalArgumentException. Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must therefore + * override this method. + * + * @param source The {@code InputSource} of the document to evaluate over. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If the implementation of this method + * does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. + * @throws NullPointerException If {@code source} is {@code null}. + * + * @since 1.9 + */ + default XPathEvaluationResult evaluateExpression(InputSource source) + throws XPathExpressionException + { + return evaluateExpression(source, XPathEvaluationResult.class); + } } diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactory.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactory.java index ce2074b19a3..ea7370e06e7 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactory.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactory.java @@ -117,7 +117,7 @@ public abstract class XPathFactory { * and returns it if it is successfully created. * *
  • - * ${java.home}/conf/jaxp.properties is read and the value associated with the key being the system property above is looked for. + * ${java.home}/lib/jaxp.properties is read and the value associated with the key being the system property above is looked for. * If present, the value is processed just like above. *
  • *
  • diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java index 282f0b05d61..bceeda854e8 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java @@ -176,9 +176,9 @@ class XPathFactoryFinder { String javah = ss.getSystemProperty( "java.home" ); String configFile = javah + File.separator + - "conf" + File.separator + "jaxp.properties"; + "lib" + File.separator + "jaxp.properties"; - // try to read from $java.home/conf/jaxp.properties + // try to read from $java.home/lib/jaxp.properties try { if(firstTime){ synchronized(cacheProps){ @@ -193,7 +193,7 @@ class XPathFactoryFinder { } } final String factoryClassName = cacheProps.getProperty(propertyName); - debugPrintln("found " + factoryClassName + " in $java.home/conf/jaxp.properties"); + debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties"); if (factoryClassName != null) { xpathFactory = createInstance(factoryClassName, true); diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java new file mode 100644 index 00000000000..6f1db4e0d45 --- /dev/null +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.xml.xpath; + +import java.util.Iterator; +import org.w3c.dom.Node; + +/** + * XPathNodes represents a set of nodes selected by a location path as specified + * in XML Path Language (XPath) + * Version 1.0, 3.3 Node-sets. + * + * @since 1.9 + */ +public interface XPathNodes extends Iterable { + + /** + * Returns an iterator of the Nodes. + * + * @return an Iterator. + */ + @Override + public abstract Iterator iterator(); + + /** + * Returns the number of items in the result + * + * @return The number of items in the result + */ + public abstract int size(); + + /** + * Returns a Node at the specified position + * + * @param index Index of the element to return. + * @return The Node at the specified position. + * @throws javax.xml.xpath.XPathException If the index is out of range + * (index < 0 || index >= size()) + */ + public abstract Node get(int index) + throws XPathException; +} diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/package.html b/jaxp/src/java.xml/share/classes/javax/xml/xpath/package.html index 82415a2d407..af0d152bc58 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/package.html +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/package.html @@ -1,6 +1,8 @@ - + + + - - - - -javax.xml.xpath - - - - - + - - -

    This package provides an object-model neutral API for the +This package provides an object-model neutral API for the evaluation of XPath expressions and access to the evaluation environment. -

    -

    The following XML standards apply:

    - - +

    +The XPath API supports + XML Path Language (XPath) Version 1.0


    -

    XPath Overview

    + +

    + +

    1. XPath Overview

    The XPath language provides a simple, concise syntax for selecting nodes from an XML document. XPath also provides rules for converting a @@ -67,7 +69,8 @@ stand-alone language, as a single XPath expression can be used to replace many lines of DOM API code.

    -

    XPath Expressions

    + +

    2. XPath Expressions

    An XPath expression is composed of a location path and one or more optional predicates. Expressions @@ -76,18 +79,22 @@ may also include XPath variables.

    The following is an example of a simple XPath expression:

    +
     /foo/bar
     
    +

    This example would select the <bar> element in an XML document such as the following:

    +
     <foo>
    -<bar/>
    +    <bar/>
     </foo>
     
    +

    The expression /foo/bar is an example of a location path. While XPath location paths resemble Unix-style file system @@ -96,30 +103,36 @@ paths, an important distinction is that XPath expressions return <bar> elements in the following document would be selected by the /foo/bar expression:

    +
     <foo>
    -<bar/>
    -<bar/>
    -<bar/>
    +    <bar/>
    +    <bar/>
    +    <bar/>
     </foo>
     
    +

    A special location path operator, //, selects nodes at any depth in an XML document. The following example selects all <bar> elements regardless of their location in a document:

    +
     //bar
     
    +

    A wildcard operator, *, causes all element nodes to be selected. The following example selects all children elements of a -<foo> element:

    +<foo> element: +
     /foo/*
     
    +

    In addition to element nodes, XPath location paths may also address attribute nodes, text nodes, comment nodes, and processing instruction @@ -166,35 +179,27 @@ location path. Predicates are of the form <foo> elements that contain an include attribute with the value of true:

    +
     //foo[@include='true']
     
    +

    Predicates may be appended to each other to further refine an expression, such as:

    +
     //foo[@include='true'][@mode='bar']
     
    +
    -

    Using the XPath API

    - -

    -The following example demonstrates using the XPath API to select one -or more nodes from an XML document:

    - -
    -XPath xpath = XPathFactory.newInstance().newXPath();
    -String expression = "/widgets/widget";
    -InputSource inputSource = new InputSource("widgets.xml");
    -NodeList nodes = (NodeList) xpath.evaluate(expression, inputSource, XPathConstants.NODESET);
    -
    - -

    XPath Expressions and Types

    + +

    3. XPath Data Types

    While XPath expressions select nodes in the XML document, the XPath API allows the selected nodes to be coalesced into one of the -following other data types:

    +following data types:

    • Boolean
    • @@ -202,14 +207,10 @@ following other data types:

    • String
    -

    The desired return type is specified by a {@link -javax.xml.namespace.QName} parameter in method call used to evaluate -the expression, which is either a call to -XPathExpression.evalute(...) or to one of the -XPath.evaluate(...) convenience methods. The allowed -QName values are specified as constants in the {@link -javax.xml.xpath.XPathConstants} class; they are:

    - + +

    3.1 QName types

    +The XPath API defines the following {@link javax.xml.namespace.QName} types to +represent return types of an XPath evaluation:
    • {@link javax.xml.xpath.XPathConstants#NODESET}
    • {@link javax.xml.xpath.XPathConstants#NODE}
    • @@ -218,26 +219,71 @@ javax.xml.xpath.XPathConstants} class; they are:

    • {@link javax.xml.xpath.XPathConstants#NUMBER}
    +

    The return type is specified by a {@link javax.xml.namespace.QName} parameter +in method call used to evaluate the expression, which is either a call to +XPathExpression.evalute(...) or XPath.evaluate(...) +methods. +

    When a Boolean return type is requested, Boolean.TRUE is returned if one or more nodes were -selected; otherwise, Boolean.FALSE is returned.

    +selected; otherwise, Boolean.FALSE is returned.

    The String return type is a convenience for retrieving the character data from a text node, attribute node, comment node, or processing-instruction node. When used on an element node, the value of the child text nodes is returned. -

    The Number return type attempts to coalesce the text of a node to a double data type. -

    -

    XPath Context

    + +

    3.2 Class types

    +In addition to the QName types, the XPath API supports the use of Class types +through the XPathExpression.evaluteExpression(...) or +XPath.evaluateExpression(...) methods. + +The XPath data types are mapped to Class types as follows: +
      +
    • Boolean -- Boolean.class
    • +
    • Number -- Number.class
    • +
    • String -- String.class
    • +
    • Nodeset -- XPathNodes.class
    • +
    • Node -- Node.class
    • +
    + +

    +Of the subtypes of Number, only Double, Integer and Long are supported. + + +

    3.3 Enum types

    +Enum types are defined in {@link javax.xml.xpath.XPathEvaluationResult.XPathResultType} +that provide mappings between the QName and Class types above. The result of +evaluating an expression using the XPathExpression.evaluteExpression(...) +or XPath.evaluateExpression(...) methods will be of one of these types. + + +

    4. XPath Context

    XPath location paths may be relative to a particular node in the -document, known as the context. Consider the following -XML document:

    +document, known as the context. A context consists of: +
      +
    • a node (the context node)
    • +
    • a pair of non-zero positive integers (the context position and the context size)
    • +
    • a set of variable bindings
    • +
    • a function library
    • +
    • the set of namespace declarations in scope for the expression
    • +
    +

    +It is an XML document tree represented as a hierarchy of nodes, a +{@link org.w3c.dom.Node} for example, in the JDK implementation. + + +

    5. Using the XPath API

    + +Consider the following XML document: +

    +

     <widgets>
     <widget>
    @@ -246,36 +292,88 @@ XML document:

    </widget> </widgets>
    +
    -

    The <widget> element can be selected with the -following XPath API code:

    +

    +The <widget> element can be selected with the following process: +

     // parse the XML as a W3C Document
     DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
     Document document = builder.parse(new File("/widgets.xml"));
     
    +//Get an XPath object and evaluate the expression
     XPath xpath = XPathFactory.newInstance().newXPath();
     String expression = "/widgets/widget";
     Node widgetNode = (Node) xpath.evaluate(expression, document, XPathConstants.NODE);
    +
    +//or using the evaluateExpression method
    +Node widgetNode = xpath.evaluateExpression(expression, document, Node.class);
     
    +

    With a reference to the <widget> element, a -relative XPath expression can now written to select the +relative XPath expression can be written to select the <manufacturer> child element:

    +
     XPath xpath = XPathFactory.newInstance().newXPath();
     String expression = "manufacturer";
     Node manufacturerNode = (Node) xpath.evaluate(expression, widgetNode, XPathConstants.NODE);
    -
    - +//or using the evaluateExpression method +Node manufacturerNode = xpath.evaluateExpression(expression, widgetNode, Node.class); + +
    + +

    +In the above example, the XML file is read into a DOM Document before being passed +to the XPath API. The following code demonstrates the use of InputSource to +leave it to the XPath implementation to process it: + +

    +
    +XPath xpath = XPathFactory.newInstance().newXPath();
    +String expression = "/widgets/widget";
    +InputSource inputSource = new InputSource("widgets.xml");
    +NodeList nodes = (NodeList) xpath.evaluate(expression, inputSource, XPathConstants.NODESET);
    +
    +//or using the evaluateExpression method
    +XPathNodes nodes = xpath.evaluate(expression, inputSource, XPathNodes.class);
    +
    +
    + +

    +In the above cases, the type of the expected results are known. In case where +the result type is unknown or any type, the {@link javax.xml.xpath.XPathEvaluationResult} +may be used to determine the return type. The following code demonstrates the usage: +

    +
    +XPathEvaluationResult<?> result = xpath.evaluateExpression(expression, document);
    +switch (result.type()) {
    +    case NODESET:
    +        XPathNodes nodes = (XPathNodes)result.value();
    +        ...
    +        break;
    +}
    +
    +
    + +

    +The XPath 1.0 Number data type is defined as a double. However, the XPath +specification also provides functions that returns Integer type. To facilitate +such operations, the XPath API allows Integer and Long to be used in +{@code evaluateExpression} method such as the following code: +

    +

    +
    +int count = xpath.evaluate("count(/widgets/widget)", document, Integer.class);
    +
    +
    + +@since 1.5 + diff --git a/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathAnyTypeTest.java b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathAnyTypeTest.java new file mode 100644 index 00000000000..ef56ca90d6d --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathAnyTypeTest.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2015, 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 javax.xml.xpath; + +import java.io.File; +import javax.xml.xpath.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +/* + * @bug 8054196 + * @summary Test for the project XPath: support any type. This test covers the new + * evaluateExpression methods of XPath, as well as XPathNodes and XPathEvaluationResult. + */ +public class XPathAnyTypeTest extends XPathTestBase { + /* + Test for resolveFunction(QName functionName,int arity); evaluate throws + NPE if functionName is null. + */ + + @Test(dataProvider = "xpath", expectedExceptions = NullPointerException.class) + public void testCheckXPathFunctionResolver02(XPath xpath) throws XPathExpressionException { + xpath.setXPathFunctionResolver((functionName, arity) -> null); + assertEquals(xpath.evaluate(null, "5"), "2"); + } + /* + Check that NPE is thrown when expression is null. + */ + + @Test(dataProvider = "xpath", expectedExceptions = NullPointerException.class) + public void test01(XPath xpath) throws XPathExpressionException { + double result = xpath.evaluateExpression(null, (Object) null, Double.class); + } + + /* + Check that NPE is thrown when the class type is null. + */ + @Test(dataProvider = "xpath", expectedExceptions = NullPointerException.class) + public void test02(XPath xpath) throws XPathExpressionException { + double result = xpath.evaluateExpression("1+1", (Object) null, null); + } + + /* + Parameter item can be null when the expression does not depends on the + context. + */ + @Test(dataProvider = "xpath") + public void test03(XPath xpath) throws XPathExpressionException { + int result = xpath.evaluateExpression("1+1", (Object) null, Integer.class); + assertTrue(result == 2); + } + + /* + * Test return type: boolean. + */ + @Test(dataProvider = "document") + public void test04(XPath xpath, Document doc) throws XPathExpressionException { + boolean result1 = xpath.evaluateExpression("boolean(/Customers/Customer[@id=3])", doc, Boolean.class); + assertTrue(result1); + } + + /* + * Test return type: numeric. Subtypes supported: Double, Integer and Long + */ + @Test(dataProvider = "document") + public void test05(XPath xpath, Document doc) throws XPathExpressionException { + double result1 = xpath.evaluateExpression("count(/Customers/Customer)", doc, Double.class); + assertTrue(result1 == 3.0); + int result2 = xpath.evaluateExpression("count(/Customers/Customer)", doc, Integer.class); + assertTrue(result2 == 3); + long result3 = xpath.evaluateExpression("count(/Customers/Customer)", doc, Long.class); + assertTrue(result3 == 3); + } + + /* + * Test return type: numeric. Of the subtypes of Number, only Double, + * Integer and Long are required. + */ + @Test(dataProvider = "invalidNumericTypes", expectedExceptions = IllegalArgumentException.class) + public void test06(XPath xpath, Class type) throws XPathExpressionException { + xpath.evaluateExpression("1+1", (Object) null, type); + } + + /* + * Test return type: String. + */ + @Test(dataProvider = "document") + public void test07(XPath xpath, Document doc) throws XPathExpressionException { + String result1 = xpath.evaluateExpression("string(/Customers/Customer[@id=3]/Phone/text())", doc, String.class); + assertTrue(result1.equals("3333333333")); + } + + /* + * Test return type: NodeSet. + */ + @Test(dataProvider = "document") + public void test08(XPath xpath, Document doc) throws XPathExpressionException { + XPathNodes nodes = xpath.evaluateExpression("/Customers/Customer", doc, XPathNodes.class); + assertTrue(nodes.size() == 3); + for (Node n : nodes) { + assertEquals(n.getLocalName(), "Customer"); + } + } + + /* + * Test return type: Node. + */ + @Test(dataProvider = "document") + public void test09(XPath xpath, Document doc) throws XPathExpressionException { + Node n = xpath.evaluateExpression("/Customers/Customer[@id=3]", doc, Node.class); + assertEquals(n.getLocalName(), "Customer"); + } + + /* + * Test return type: Unsupported type. + */ + @Test(dataProvider = "document", expectedExceptions = IllegalArgumentException.class) + public void test10(XPath xpath, Document doc) throws XPathExpressionException { + File n = xpath.evaluateExpression("/Customers/Customer[@id=3]", doc, File.class); + } + + /* + * Test return type: Any::Boolean. + */ + @Test(dataProvider = "document") + public void test11(XPath xpath, Document doc) throws XPathExpressionException { + XPathEvaluationResult result = xpath.evaluateExpression("boolean(/Customers/Customer[@id=3])", doc); + verifyResult(result, true); + } + + /* + * Test return type: Any::Number. + */ + @Test(dataProvider = "document") + public void test12(XPath xpath, Document doc) throws XPathExpressionException { + XPathEvaluationResult result = xpath.evaluateExpression("count(/Customers/Customer)", doc); + verifyResult(result, 3.0); + } + + /* + * Test return type: Any::String. + */ + @Test(dataProvider = "document") + public void test13(XPath xpath, Document doc) throws XPathExpressionException { + XPathEvaluationResult result = xpath.evaluateExpression( + "string(/Customers/Customer[@id=3]/Phone/text())", doc, XPathEvaluationResult.class); + verifyResult(result, "3333333333"); + } + + /* + * Test return type: Any::Nodeset. + */ + @Test(dataProvider = "document") + public void test14(XPath xpath, Document doc) throws XPathExpressionException { + XPathEvaluationResult result = xpath.evaluateExpression("/Customers/Customer", doc); + verifyResult(result, "Customer"); + } + + /* + * Test return type: Any::Node. + */ + @Test(dataProvider = "document") + public void test15(XPath xpath, Document doc) throws XPathExpressionException { + XPathEvaluationResult result = xpath.evaluateExpression("/Customers/Customer[@id=3]", doc); + verifyResult(result, "Customer"); + } +} diff --git a/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathExpAnyTypeTest.java b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathExpAnyTypeTest.java new file mode 100644 index 00000000000..0eb8047d14a --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathExpAnyTypeTest.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2015, 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 javax.xml.xpath; + +import java.io.File; +import javax.xml.xpath.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +/* + * @bug 8054196 + * @summary Test for the project XPath: support any type. This test covers the new + * evaluateExpression methods of XPathExpression. + */ +public class XPathExpAnyTypeTest extends XPathTestBase { + + /* + * Check that NPE is thrown when the class type is null. + */ + @Test(dataProvider = "xpath", expectedExceptions = NullPointerException.class) + public void test02(XPath xpath) throws XPathExpressionException { + XPathExpression exp = xpath.compile("1+1"); + double result = exp.evaluateExpression((Object)null, null); + } + + /* + * Parameter item can be null when the expression does not depends on the + * context. + */ + @Test(dataProvider = "xpath") + public void test03(XPath xpath) throws XPathExpressionException { + XPathExpression exp = xpath.compile("1+1"); + int result = exp.evaluateExpression((Object)null, Integer.class); + assertTrue(result == 2); + } + + /* + * Test return type: boolean. + */ + @Test(dataProvider = "document") + public void test04(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("boolean(/Customers/Customer[@id=3])"); + boolean result1 = exp.evaluateExpression(doc, Boolean.class); + assertTrue(result1); + } + + /* + * Test return type: numeric. + */ + @Test(dataProvider = "document") + public void test05(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("count(/Customers/Customer)"); + double result1 = exp.evaluateExpression(doc, Double.class); + assertTrue(result1 == 3.0); + + int result2 = exp.evaluateExpression(doc, Integer.class); + assertTrue(result2 == 3); + } + + /* + * Test return type: String. + */ + @Test(dataProvider = "document") + public void test06(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("string(/Customers/Customer[@id=3]/Phone/text())"); + String result1 = exp.evaluateExpression(doc, String.class); + assertTrue(result1.equals("3333333333")); + } + + /* + * Test return type: NodeSet. + */ + @Test(dataProvider = "document") + public void test07(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("/Customers/Customer"); + XPathNodes nodes = exp.evaluateExpression(doc, XPathNodes.class); + assertTrue(nodes.size() == 3); + for (Node n : nodes) { + assertEquals(n.getLocalName(), "Customer"); + } + } + + /* + * Test return type: Node. + */ + @Test(dataProvider = "document") + public void test08(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("/Customers/Customer[@id=3]"); + Node n = exp.evaluateExpression(doc, Node.class); + assertEquals(n.getLocalName(), "Customer"); + } + + /* + * Test return type: Unsupported type. + */ + @Test(dataProvider = "document", expectedExceptions = IllegalArgumentException.class) + public void test09(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("/Customers/Customer[@id=3]"); + File n = exp.evaluateExpression(doc, File.class); + } + + /* + * Test return type: Any::Boolean. + */ + @Test(dataProvider = "document") + public void test10(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("boolean(/Customers/Customer[@id=3])"); + XPathEvaluationResult result = exp.evaluateExpression(doc); + verifyResult(result, true); + } + + /* + * Test return type: Any::Number. + */ + @Test(dataProvider = "document") + public void test11(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("count(/Customers/Customer)"); + XPathEvaluationResult result = exp.evaluateExpression(doc); + verifyResult(result, 3.0); + } + + /* + * Test return type: Any::String. + */ + @Test(dataProvider = "document") + public void test12(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("string(/Customers/Customer[@id=3]/Phone/text())"); + XPathEvaluationResult result = exp.evaluateExpression(doc, XPathEvaluationResult.class); + verifyResult(result, "3333333333"); + } + + /* + * Test return type: Any::Nodeset. + */ + @Test(dataProvider = "document") + public void test13(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("/Customers/Customer"); + XPathEvaluationResult result = exp.evaluateExpression(doc); + verifyResult(result, "Customer"); + } + + /* + * Test return type: Any::Node. + */ + @Test(dataProvider = "document") + public void test14(XPath xpath, Document doc) throws XPathExpressionException { + XPathExpression exp = xpath.compile("/Customers/Customer[@id=3]"); + XPathEvaluationResult result = exp.evaluateExpression(doc); + verifyResult(result, "Customer"); + } + +} diff --git a/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathTestBase.java b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathTestBase.java new file mode 100644 index 00000000000..0f0624216c8 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathTestBase.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015, 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 javax.xml.xpath; + +import java.io.ByteArrayInputStream; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import javax.xml.parsers.DocumentBuilderFactory; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +import org.testng.annotations.DataProvider; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +/* + * Base class for XPath test + */ +class XPathTestBase { + + static final String rawXML + = "" + + "" + + " " + + " name1" + + " 1111111111" + + " 123@xyz.com" + + "
    " + + " 1111 111st ave" + + " The City" + + " The State" + + "
    " + + "
    " + + " " + + " name1" + + " 2222222222" + + " 123@xyz.com" + + "
    " + + " 2222 222nd ave" + + " The City" + + " The State" + + "
    " + + "
    " + + " " + + " name1" + + " 3333333333" + + " 123@xyz.com" + + "
    " + + " 3333 333rd ave" + + " The City" + + " The State" + + "
    " + + "
    " + + "
    "; + + void verifyResult(XPathEvaluationResult result, Object expected) { + switch (result.type()) { + case BOOLEAN: + assertTrue(((Boolean) result.value()).equals(expected)); + return; + case NUMBER: + assertTrue(((Double) result.value()).equals(expected)); + return; + case STRING: + assertTrue(((String) result.value()).equals(expected)); + return; + case NODESET: + XPathNodes nodes = (XPathNodes) result.value(); + for (Node n : nodes) { + assertEquals(n.getLocalName(), expected); + } + return; + case NODE: + assertTrue(((Node) result.value()).getLocalName().equals(expected)); + return; + } + assertFalse(true, "Unsupported type"); + } + + /* + * DataProvider: XPath object + */ + @DataProvider(name = "xpath") + Object[][] getXPath() { + return new Object[][]{{XPathFactory.newInstance().newXPath()}}; + } + + /* + * DataProvider: Numeric types not supported + */ + @DataProvider(name = "invalidNumericTypes") + Object[][] getInvalidNumericTypes() { + XPath xpath = XPathFactory.newInstance().newXPath(); + return new Object[][]{{xpath, AtomicInteger.class}, + {xpath, AtomicInteger.class}, + {xpath, AtomicLong.class}, + {xpath, BigDecimal.class}, + {xpath, BigInteger.class}, + {xpath, Byte.class}, + {xpath, Float.class}, + {xpath, Short.class} + }; + } + + /* + * DataProvider: XPath and Document objects + */ + @DataProvider(name = "document") + Object[][] getDocument() throws Exception { + DocumentBuilderFactory dBF = DocumentBuilderFactory.newInstance(); + dBF.setValidating(false); + dBF.setNamespaceAware(true); + Document doc = dBF.newDocumentBuilder().parse( + new ByteArrayInputStream(rawXML.getBytes("UTF-8"))); + + return new Object[][]{{XPathFactory.newInstance().newXPath(), doc}}; + } +} From 04d8bf6c334f8ec38d2c93e227af0673a3e78386 Mon Sep 17 00:00:00 2001 From: Katja Kantserova Date: Wed, 28 Jan 2015 09:23:41 +0100 Subject: [PATCH 46/72] 8071582: com/sun/jdi/GetLocalVariables4Test.sh should be quarantined Reviewed-by: sspitsyn, sla --- jdk/test/ProblemList.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index c83e162b72a..7b0a4f7a035 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -301,6 +301,9 @@ com/sun/jdi/CatchPatternTest.sh generic-all # 8069402 com/sun/jdi/ConnectedVMs.java generic-all +# 8067354 +com/sun/jdi/GetLocalVariables4Test.sh windows-all + ############################################################################ # jdk_util From f5b35f790c4972cd11f0f091e1475bd96ab88af9 Mon Sep 17 00:00:00 2001 From: Dmitry Samersoff Date: Wed, 28 Jan 2015 04:56:00 -0800 Subject: [PATCH 47/72] 8042397: tmtools/jmap/heap_config/jmap_heap_config_OldSize fails Rewrite the test to jtreg Reviewed-by: ykantser, jbachorik --- .../jmap/heapconfig/JMapHeapConfigTest.java | 132 ++++++ .../tools/jmap/heapconfig/LingeredApp.java | 402 ++++++++++++++++++ .../jmap/heapconfig/LingeredAppTest.java | 72 ++++ .../jmap/heapconfig/TmtoolTestScenario.java | 137 ++++++ 4 files changed, 743 insertions(+) create mode 100644 jdk/test/sun/tools/jmap/heapconfig/JMapHeapConfigTest.java create mode 100644 jdk/test/sun/tools/jmap/heapconfig/LingeredApp.java create mode 100644 jdk/test/sun/tools/jmap/heapconfig/LingeredAppTest.java create mode 100644 jdk/test/sun/tools/jmap/heapconfig/TmtoolTestScenario.java diff --git a/jdk/test/sun/tools/jmap/heapconfig/JMapHeapConfigTest.java b/jdk/test/sun/tools/jmap/heapconfig/JMapHeapConfigTest.java new file mode 100644 index 00000000000..fe856d736b3 --- /dev/null +++ b/jdk/test/sun/tools/jmap/heapconfig/JMapHeapConfigTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8042397 + * @summary Unit test for jmap utility test heap configuration reader + * @library /lib/testlibrary + * @build jdk.testlibrary.* + * @build JMapHeapConfigTest LingeredApp TmtoolTestScenario + * @run main JMapHeapConfigTest + */ +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import jdk.testlibrary.Utils; + +public class JMapHeapConfigTest { + + static final String expectedJMapValues[] = { + "MinHeapFreeRatio", + "MaxHeapFreeRatio", + "MaxHeapSize", + "NewSize", + "MaxNewSize", + "OldSize", + "NewRatio", + "SurvivorRatio", + "MetaspaceSize", + "CompressedClassSpaceSize", + "G1HeapRegionSize"}; + + // ignoring MaxMetaspaceSize + + private static Map parseJMapOutput(List jmapOutput) { + Map heapConfigMap = new HashMap(); + boolean shouldParse = false; + + for (String line : jmapOutput) { + line = line.trim(); + + if (line.startsWith("Heap Configuration:")) { + shouldParse = true; + continue; + } + + if (line.startsWith("Heap Usage:")) { + shouldParse = false; + continue; + } + + if (shouldParse && !line.equals("")) { + String[] lv = line.split("\\s+"); + try { + heapConfigMap.put(lv[0], lv[2]); + } catch (ArrayIndexOutOfBoundsException ex) { + // Ignore mailformed lines + } + } + } + return heapConfigMap; + } + + // Compare stored values + private static void compareValues(Map parsedJMapOutput, Map parsedVmOutput) { + for (String key : expectedJMapValues) { + try { + String jmapVal = parsedJMapOutput.get(key); + if (jmapVal == null) { + throw new RuntimeException("Key '" + key + "' doesn't exists in jmap output"); + } + + String vmVal = parsedVmOutput.get(key); + if (vmVal == null) { + throw new RuntimeException("Key '" + key + "' doesn't exists in vm output"); + } + + if (new BigDecimal(jmapVal).compareTo(new BigDecimal(vmVal)) != 0) { + throw new RuntimeException(String.format("Key %s doesn't match %s vs %s", key, vmVal, jmapVal)); + } + } catch (NumberFormatException ex) { + throw new RuntimeException("Unexpected key '" + key + "' value", ex); + } + } + } + + public static void main(String[] args) { + System.out.println("Starting JMapHeapConfigTest"); + + // Forward vm options to LingeredApp + ArrayList cmd = new ArrayList(); + cmd.addAll(Utils.getVmOptions()); + cmd.add("-XX:+PrintFlagsFinal"); + + TmtoolTestScenario tmt = TmtoolTestScenario.create("jmap", "-heap"); + int exitcode = tmt.launch(cmd); + if (exitcode != 0) { + throw new RuntimeException("Test FAILED jmap exits with non zero exit code " + exitcode); + } + + Map parsedJmapOutput = parseJMapOutput(tmt.getToolOutput()); + Map parsedVMOutput = tmt.parseFlagsFinal(); + + compareValues(parsedJmapOutput, parsedVMOutput); + + // If test fails it throws RuntimeException + System.out.println("Test PASSED"); + } +} diff --git a/jdk/test/sun/tools/jmap/heapconfig/LingeredApp.java b/jdk/test/sun/tools/jmap/heapconfig/LingeredApp.java new file mode 100644 index 00000000000..176f82fc348 --- /dev/null +++ b/jdk/test/sun/tools/jmap/heapconfig/LingeredApp.java @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2015, 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. + */ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * This is a framework to launch an app that could be synchronized with caller + * to make further attach actions reliable across supported platforms + + * Caller example: + * SmartTestApp a = SmartTestApp.startApp(cmd); + * // do something + * a.stopApp(); + * + * or fine grained control + * + * a = new SmartTestApp("MyLock.lck"); + * a.createLock(); + * a.runApp(); + * a.waitAppReady(); + * // do something + * a.deleteLock(); + * a.waitAppTerminate(); + * + * Then you can work with app output and process object + * + * output = a.getAppOutput(); + * process = a.getProcess(); + * + */ +public class LingeredApp { + + private static final long spinDelay = 1000; + + private final String lockFileName; + private long lockCreationTime; + private Process appProcess; + private final ArrayList storedAppOutput; + + /* + * Drain child process output, store it into string array + */ + class InputGobbler extends Thread { + + InputStream is; + List astr; + + InputGobbler(InputStream is, List astr) { + this.is = is; + this.astr = astr; + } + + public void run() { + try { + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + String line = null; + while ((line = br.readLine()) != null) { + astr.add(line); + } + } catch (IOException ex) { + // pass + } + } + } + + /** + * Create LingeredApp object on caller side. Lock file have be a valid filename + * at writable location + * + * @param lockFileName - the name of lock file + */ + public LingeredApp(String lockFileName) { + this.lockFileName = lockFileName; + this.storedAppOutput = new ArrayList(); + } + + /** + * + * @return name of lock file + */ + public String getLockFileName() { + return this.lockFileName; + } + + /** + * + * @return name of testapp + */ + public String getAppName() { + return this.getClass().getName(); + } + + /** + * + * @return pid of java process running testapp + */ + public long getPid() { + if (appProcess == null) { + throw new RuntimeException("Process is not alive"); + } + return appProcess.getPid(); + } + + /** + * + * @return process object + */ + public Process getProcess() { + return appProcess; + } + + /** + * + * @return application output as string array. Empty array if application produced no output + */ + List getAppOutput() { + if (appProcess.isAlive()) { + throw new RuntimeException("Process is still alive. Can't get its output."); + } + return storedAppOutput; + } + + /* Make sure all part of the app use the same method to get dates, + as different methods could produce different results + */ + private static long epoch() { + return new Date().getTime(); + } + + private static long lastModified(String fileName) throws IOException { + Path path = Paths.get(fileName); + BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class); + return attr.lastModifiedTime().toMillis(); + } + + private static void setLastModified(String fileName, long newTime) throws IOException { + Path path = Paths.get(fileName); + FileTime fileTime = FileTime.fromMillis(newTime); + Files.setLastModifiedTime(path, fileTime); + } + + /** + * create lock + * + * @throws IOException + */ + public void createLock() throws IOException { + Path path = Paths.get(lockFileName); + // Files.deleteIfExists(path); + Files.createFile(path); + lockCreationTime = lastModified(lockFileName); + } + + /** + * Delete lock + * + * @throws IOException + */ + public void deleteLock() throws IOException { + try { + Path path = Paths.get(lockFileName); + Files.delete(path); + } catch (NoSuchFileException ex) { + // Lock already deleted. Ignore error + } + } + + public void waitAppTerminate() { + while (true) { + try { + appProcess.waitFor(); + break; + } catch (InterruptedException ex) { + // pass + } + } + } + + /** + * The app touches the lock file when it's started + * wait while it happens. Caller have to delete lock on wait error. + * + * @param timeout + * @throws java.io.IOException + */ + public void waitAppReady(long timeout) throws IOException { + long here = epoch(); + while (true) { + long epoch = epoch(); + if (epoch - here > (timeout * 1000)) { + throw new IOException("App waiting timeout"); + } + + // Live process should touch lock file every second + long lm = lastModified(lockFileName); + if (lm > lockCreationTime) { + break; + } + + // Make sure process didn't already exit + if (!appProcess.isAlive()) { + throw new IOException("App exited unexpectedly with " + appProcess.exitValue()); + } + + try { + Thread.sleep(spinDelay); + } catch (InterruptedException ex) { + // pass + } + } + } + + /** + * Run the app + * + * @param vmArguments + * @throws IOException + */ + public void runApp(List vmArguments) + throws IOException { + + // We should always use testjava or throw an exception, + // so we can't use JDKToolFinder.getJDKTool("java"); + // that falls back to compile java on error + String jdkPath = System.getProperty("test.jdk"); + if (jdkPath == null) { + // we are not under jtreg, try env + Map env = System.getenv(); + jdkPath = env.get("TESTJAVA"); + } + + if (jdkPath == null) { + throw new RuntimeException("Can't determine jdk path neither test.jdk property no TESTJAVA env are set"); + } + + String osname = System.getProperty("os.name"); + String javapath = jdkPath + ((osname.startsWith("window")) ? "/bin/java.exe" : "/bin/java"); + + List cmd = new ArrayList(); + cmd.add(javapath); + + + if (vmArguments == null) { + // Propagate test.vm.options to LingeredApp, filter out possible empty options + String testVmOpts[] = System.getProperty("test.vm.opts","").split("\\s+"); + for (String s : testVmOpts) { + if (!s.equals("")) { + cmd.add(s); + } + } + } + else{ + // Lets user manage LingerApp options + cmd.addAll(vmArguments); + } + + // Make sure we set correct classpath to run the app + cmd.add("-cp"); + String classpath = System.getProperty("test.class.path"); + cmd.add((classpath == null) ? "." : classpath); + + cmd.add(this.getAppName()); + cmd.add(lockFileName); + + // Reporting + StringBuilder cmdLine = new StringBuilder(); + for (String strCmd : cmd) { + cmdLine.append("'").append(strCmd).append("' "); + } + + // A bit of verbosity + System.out.println("Command line: [" + cmdLine.toString() + "]"); + + ProcessBuilder pb = new ProcessBuilder(cmd); + // we don't expect any error output but make sure we are not stuck on pipe + // pb.redirectErrorStream(false); + pb.redirectError(ProcessBuilder.Redirect.INHERIT); + + appProcess = pb.start(); + + // Create pipe reader for process, and read stdin and stderr to array of strings + InputGobbler gb = new InputGobbler(appProcess.getInputStream(), storedAppOutput); + gb.start(); + } + + /** + * High level interface for test writers + */ + /** + * Factory method that creates SmartAppTest object with ready to use application + * lock name is autogenerated, wait timeout is hardcoded + * @param cmd - vm options, could be null to auto add testvm.options + * @return LingeredApp object + * @throws IOException + */ + public static LingeredApp startApp(List cmd) throws IOException { + final String lockName = UUID.randomUUID().toString() + ".lck"; + final int waitTime = 10; + + LingeredApp a = new LingeredApp(lockName); + a.createLock(); + try { + a.runApp(cmd); + a.waitAppReady(waitTime); + } catch (Exception ex) { + a.deleteLock(); + throw ex; + } + + return a; + } + + public static LingeredApp startApp() throws IOException { + return startApp(null); + } + + /** + * Delete lock file that signal app to terminate, then + * waits until app is actually terminated. + * @throws IOException + */ + public void stopApp() throws IOException { + deleteLock(); + waitAppTerminate(); + int exitcode = appProcess.exitValue(); + if (exitcode != 0) { + throw new IOException("LingeredApp terminated with non-zero exit code " + exitcode); + } + } + + /** + * This part is the application it self + */ + public static void main(String args[]) { + + if (args.length != 1) { + System.err.println("Lock file name is not specified"); + System.exit(7); + } + + String theLockFileName = args[0]; + + try { + Path path = Paths.get(theLockFileName); + + while (Files.exists(path)) { + long lm = lastModified(theLockFileName); + long now = epoch(); + + // A bit of paranoja, don't allow test app to run more than an hour + if (now - lm > 3600) { + throw new IOException("Lock is too old. Aborting"); + } + + // Touch lock to indicate our rediness + setLastModified(theLockFileName, now); + Thread.sleep(spinDelay); + } + + } catch (Exception ex) { + System.err.println("LingeredApp ERROR: " + ex); + // Leave exit_code = 1 to Java launcher + System.exit(3); + } + + System.exit(0); + } +} diff --git a/jdk/test/sun/tools/jmap/heapconfig/LingeredAppTest.java b/jdk/test/sun/tools/jmap/heapconfig/LingeredAppTest.java new file mode 100644 index 00000000000..e492add66c3 --- /dev/null +++ b/jdk/test/sun/tools/jmap/heapconfig/LingeredAppTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Unit test for LingeredApp + * @compile LingeredAppTest.java + * @compile LingeredApp.java + * @run main LingeredAppTest + */ +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class LingeredAppTest { + + public static void main(String[] args) { + try { + System.out.println("Starting LingeredApp with default parameters"); + + ArrayList cmd = new ArrayList(); + + // Propagate test.vm.options to LingeredApp, filter out possible empty options + String testVmOpts[] = System.getProperty("test.vm.opts","").split("\\s+"); + for (String s : testVmOpts) { + if (!s.equals("")) { + cmd.add(s); + } + } + + cmd.add("-XX:+PrintFlagsFinal"); + + LingeredApp a = LingeredApp.startApp(cmd); + System.out.printf("App pid: %d\n", a.getPid()); + a.stopApp(); + + System.out.println("App output:"); + int count = 0; + for (String line : a.getAppOutput()) { + count += 1; + } + System.out.println("Found " + count + " lines in VM output"); + System.out.println("Test PASSED"); + } catch (IOException ex) { + ex.printStackTrace(); + System.out.println("Test ERROR"); + System.exit(3); + } + } +} diff --git a/jdk/test/sun/tools/jmap/heapconfig/TmtoolTestScenario.java b/jdk/test/sun/tools/jmap/heapconfig/TmtoolTestScenario.java new file mode 100644 index 00000000000..667085f4fe8 --- /dev/null +++ b/jdk/test/sun/tools/jmap/heapconfig/TmtoolTestScenario.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015, 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. + */ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import jdk.testlibrary.JDKToolLauncher; +import jdk.testlibrary.Utils; + +public class TmtoolTestScenario { + + private final ArrayList toolOutput = new ArrayList(); + private LingeredApp theApp = null; + private final String toolName; + private final String[] toolArgs; + + /** + * @param toolName - name of tool to test + * @param toolArgs - tool arguments + * @return the object + */ + public static TmtoolTestScenario create(String toolName, String... toolArgs) { + return new TmtoolTestScenario(toolName, toolArgs); + } + + /** + * @return STDOUT of tool + */ + public List getToolOutput() { + return toolOutput; + } + + /** + * + * @return STDOUT of test app + */ + public List getAppOutput() { + return theApp.getAppOutput(); + } + + /** + * @return Value of the app output with -XX:+PrintFlagsFinal as a map. + */ + public Map parseFlagsFinal() { + List astr = theApp.getAppOutput(); + Map vmMap = new HashMap(); + + for (String line : astr) { + String[] lv = line.trim().split("\\s+"); + try { + vmMap.put(lv[1], lv[3]); + } catch (ArrayIndexOutOfBoundsException ex) { + // ignore mailformed lines + } + } + return vmMap; + } + + /** + * + * @param vmArgs - vm and java arguments to launch test app + * @return exit code of tool + */ + public int launch(List vmArgs) { + System.out.println("Starting LingeredApp"); + try { + try { + theApp = LingeredApp.startApp(vmArgs); + + System.out.println("Starting " + toolName + " against " + theApp.getPid()); + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK(toolName); + + for (String cmd : toolArgs) { + launcher.addToolArg(cmd); + } + launcher.addToolArg(Long.toString(theApp.getPid())); + + ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand()); + processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT); + Process toolProcess = processBuilder.start(); + + // By default child process output stream redirected to pipe, so we are reading it in foreground. + BufferedReader reader = new BufferedReader(new InputStreamReader(toolProcess.getInputStream())); + + String line; + while ((line = reader.readLine()) != null) { + toolOutput.add(line.trim()); + } + + toolProcess.waitFor(); + + return toolProcess.exitValue(); + } finally { + theApp.stopApp(); + } + } catch (IOException | InterruptedException ex) { + throw new RuntimeException("Test ERROR " + ex, ex); + } + } + + public void launch(String... appArgs) throws IOException { + launch(Arrays.asList(appArgs)); + } + + private TmtoolTestScenario(String toolName, String[] toolArgs) { + this.toolName = toolName; + this.toolArgs = toolArgs; + } + +} From d60c8e9ea6f97b60d26c2a0415aa6b400a427701 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Wed, 28 Jan 2015 14:04:05 +0100 Subject: [PATCH 48/72] 8071651: infinite build loops in 9-dev windows platform on Jan 26 Reviewed-by: alanb, ihse --- make/common/MakeBase.gmk | 8 +++++--- test/make/TestMakeBase.gmk | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index f40c8c0be27..58ddb2cc0b9 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -445,7 +445,9 @@ not-containing = $(strip $(foreach v,$(strip $2),$(if $(findstring $(strip $1),$ uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) # String equals -equals = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) +equals = \ + $(and $(findstring $(strip $1),$(strip $2)),\ + $(findstring $(strip $2),$(strip $1))) ifneq ($(DISABLE_CACHE_FIND), true) ################################################################################ @@ -606,8 +608,8 @@ DependOnVariableHelper = \ $(call ReadFile, $(call DependOnVariableFileName, $1, $2)))),,\ $(call MakeDir, $(dir $(call DependOnVariableFileName, $1, $2))) \ $(if $(findstring $(LOG_LEVEL), trace), \ - $(info Variable $1: $(strip $($1))) \ - $(info File: $(call ReadFile, $(call DependOnVariableFileName, $1, $2)))) \ + $(info Variable $1: >$(strip $($1))<) \ + $(info File: >$(call ReadFile, $(call DependOnVariableFileName, $1, $2))<)) \ $(call WriteFile, $($1), $(call DependOnVariableFileName, $1, $2))) \ $(call DependOnVariableFileName, $1, $2)) diff --git a/test/make/TestMakeBase.gmk b/test/make/TestMakeBase.gmk index 3309314652d..407ec9336a4 100644 --- a/test/make/TestMakeBase.gmk +++ b/test/make/TestMakeBase.gmk @@ -62,6 +62,20 @@ $(ESCAPE_DOLLAR_DIR)/_escape_dollar: $(DEPS) TEST_TARGETS += $(ESCAPE_DOLLAR_DIR)/_escape_dollar +################################################################################ +# Test Equals + +EQUALS_VALUE1 := value1$(SPACE) +EQUALS_VALUE2 := value2 + +ifneq ($(call equals, $(EQUALS_VALUE1), $(EQUALS_VALUE2)), ) + $(error The strings >$(EQUALS_VALUE1)< and >$(EQUALS_VALUE2)< are equal) +endif + +ifeq ($(call equals, $(EQUALS_VALUE1), $(EQUALS_VALUE1)), ) + $(error The strings >$(EQUALS_VALUE1)< and >$(EQUALS_VALUE1)< are not equal) +endif + ################################################################################ # Test ShellQuote From 7cd26c0c6e0fb672c3c6095b33121610beaa9401 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Wed, 28 Jan 2015 15:45:00 +0100 Subject: [PATCH 49/72] 8071781: Bootcycle build fails on macosx Reviewed-by: ihse --- common/autoconf/bootcycle-spec.gmk.in | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/autoconf/bootcycle-spec.gmk.in b/common/autoconf/bootcycle-spec.gmk.in index 31ff7525610..6e68c3a0b34 100644 --- a/common/autoconf/bootcycle-spec.gmk.in +++ b/common/autoconf/bootcycle-spec.gmk.in @@ -48,8 +48,9 @@ BOOT_JDK := $(JDK_IMAGE_DIR) # The bootcycle build has a different output directory OLD_BUILD_OUTPUT:=@BUILD_OUTPUT@ BUILD_OUTPUT:=$(OLD_BUILD_OUTPUT)/bootcycle-build -# The HOTSPOT_DIST dir is not defined relative to BUILD_OUTPUT in spec.gmk -HOTSPOT_DIST:=$(patsubst $(OLD_BUILD_OUTPUT)%, $(BUILD_OUTPUT)%, $(HOTSPOT_DIST)) +# The HOTSPOT_DIST dir is not defined relative to BUILD_OUTPUT in spec.gmk. Must not +# use space in this patsubst to avoid leading space in HOTSPOT_DIST. +HOTSPOT_DIST:=$(patsubst $(OLD_BUILD_OUTPUT)%,$(BUILD_OUTPUT)%,$(HOTSPOT_DIST)) SJAVAC_SERVER_DIR:=$(patsubst $(OLD_BUILD_OUTPUT)%, $(BUILD_OUTPUT)%, $(SJAVAC_SERVER_DIR)) JAVA_CMD:=$(BOOT_JDK)/bin/java From b5f5424c83e28240a3eb280251ffe604a294ac20 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 28 Jan 2015 17:48:59 +0100 Subject: [PATCH 50/72] 8068730: Increase the precision of the implementation of java.time.Clock.systemUTC() Changes the implementation of java.time.Clock.systemUTC() to take advantage of the maximum resolution of the underlying native clock on which System.currentTimeMillis() is based. Reviewed-by: dholmes, rriggs, scolebourne, sla --- .../share/classes/java/time/Clock.java | 64 +++- .../share/classes/java/util/Formatter.java | 10 +- .../java.base/share/classes/sun/misc/VM.java | 32 +- jdk/src/java.base/share/native/include/jvm.h | 5 +- jdk/src/java.base/share/native/libjava/VM.c | 15 +- .../time/tck/java/time/TCKLocalDateTime.java | 5 +- .../java/time/tck/java/time/TCKLocalTime.java | 5 +- .../time/tck/java/time/TCKZonedDateTime.java | 5 +- .../time/test/java/time/TestClock_System.java | 298 +++++++++++++++++- .../time/test/java/util/TestFormatter.java | 41 ++- .../sun/misc/VM/GetNanoTimeAdjustment.java | 249 +++++++++++++++ 11 files changed, 714 insertions(+), 15 deletions(-) create mode 100644 jdk/test/sun/misc/VM/GetNanoTimeAdjustment.java diff --git a/jdk/src/java.base/share/classes/java/time/Clock.java b/jdk/src/java.base/share/classes/java/time/Clock.java index b1127848bed..28dd55f9b8d 100644 --- a/jdk/src/java.base/share/classes/java/time/Clock.java +++ b/jdk/src/java.base/share/classes/java/time/Clock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -61,12 +61,15 @@ */ package java.time; +import java.io.IOException; +import java.io.ObjectInputStream; import static java.time.LocalTime.NANOS_PER_MINUTE; import static java.time.LocalTime.NANOS_PER_SECOND; import java.io.Serializable; import java.util.Objects; import java.util.TimeZone; +import sun.misc.VM; /** * A clock providing access to the current instant, date and time using a time-zone. @@ -446,10 +449,22 @@ public abstract class Clock { */ static final class SystemClock extends Clock implements Serializable { private static final long serialVersionUID = 6740630888130243051L; + private static final long OFFSET_SEED = + System.currentTimeMillis()/1000 - 1024; // initial offest private final ZoneId zone; + // We don't actually need a volatile here. + // We don't care if offset is set or read concurrently by multiple + // threads - we just need a value which is 'recent enough' - in other + // words something that has been updated at least once in the last + // 2^32 secs (~136 years). And even if we by chance see an invalid + // offset, the worst that can happen is that we will get a -1 value + // from getNanoTimeAdjustment, forcing us to update the offset + // once again. + private transient long offset; SystemClock(ZoneId zone) { this.zone = zone; + this.offset = OFFSET_SEED; } @Override public ZoneId getZone() { @@ -464,11 +479,50 @@ public abstract class Clock { } @Override public long millis() { + // System.currentTimeMillis() and VM.getNanoTimeAdjustment(offset) + // use the same time source - System.currentTimeMillis() simply + // limits the resolution to milliseconds. + // So we take the faster path and call System.currentTimeMillis() + // directly - in order to avoid the performance penalty of + // VM.getNanoTimeAdjustment(offset) which is less efficient. return System.currentTimeMillis(); } @Override public Instant instant() { - return Instant.ofEpochMilli(millis()); + // Take a local copy of offset. offset can be updated concurrently + // by other threads (even if we haven't made it volatile) so we will + // work with a local copy. + long localOffset = offset; + long adjustment = VM.getNanoTimeAdjustment(localOffset); + + if (adjustment == -1) { + // -1 is a sentinel value returned by VM.getNanoTimeAdjustment + // when the offset it is given is too far off the current UTC + // time. In principle, this should not happen unless the + // JVM has run for more than ~136 years (not likely) or + // someone is fiddling with the system time, or the offset is + // by chance at 1ns in the future (very unlikely). + // We can easily recover from all these conditions by bringing + // back the offset in range and retry. + + // bring back the offset in range. We use -1024 to make + // it more unlikely to hit the 1ns in the future condition. + localOffset = System.currentTimeMillis()/1000 - 1024; + + // retry + adjustment = VM.getNanoTimeAdjustment(localOffset); + + if (adjustment == -1) { + // Should not happen: we just recomputed a new offset. + // It should have fixed the issue. + throw new InternalError("Offset " + localOffset + " is not in range"); + } else { + // OK - recovery succeeded. Update the offset for the + // next call... + offset = localOffset; + } + } + return Instant.ofEpochSecond(localOffset, adjustment); } @Override public boolean equals(Object obj) { @@ -485,6 +539,12 @@ public abstract class Clock { public String toString() { return "SystemClock[" + zone + "]"; } + private void readObject(ObjectInputStream is) + throws IOException, ClassNotFoundException { + // ensure that offset is initialized + is.defaultReadObject(); + offset = OFFSET_SEED; + } } //----------------------------------------------------------------------- diff --git a/jdk/src/java.base/share/classes/java/util/Formatter.java b/jdk/src/java.base/share/classes/java/util/Formatter.java index a973ee6889e..3b751b6e86a 100644 --- a/jdk/src/java.base/share/classes/java/util/Formatter.java +++ b/jdk/src/java.base/share/classes/java/util/Formatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, 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 @@ -57,6 +57,7 @@ import java.time.ZoneOffset; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalQueries; +import java.time.temporal.UnsupportedTemporalTypeException; import sun.misc.DoubleConsts; import sun.misc.FormattedFloatingDecimal; @@ -4056,7 +4057,12 @@ public final class Formatter implements Closeable, Flushable { break; } case DateTime.NANOSECOND: { // 'N' (000000000 - 999999999) - int i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000; + int i; + try { + i = t.get(ChronoField.NANO_OF_SECOND); + } catch (UnsupportedTemporalTypeException u) { + i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000; + } Flags flags = Flags.ZERO_PAD; sb.append(localizedMagnitude(null, i, flags, 9, l)); break; diff --git a/jdk/src/java.base/share/classes/sun/misc/VM.java b/jdk/src/java.base/share/classes/sun/misc/VM.java index c877e40446f..36bfb606495 100644 --- a/jdk/src/java.base/share/classes/sun/misc/VM.java +++ b/jdk/src/java.base/share/classes/sun/misc/VM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015, 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 @@ -402,6 +402,36 @@ public class VM { */ public static native long getegid(); + /** + * Get a nanosecond time stamp adjustment in the form of a single long. + * + * This value can be used to create an instant using + * {@link java.time.Instant#ofEpochSecond(long, long) + * java.time.Instant.ofEpochSecond(offsetInSeconds, + * getNanoTimeAdjustment(offsetInSeconds))}. + *

    + * The value returned has the best resolution available to the JVM on + * the current system. + * This is usually down to microseconds - or tenth of microseconds - + * depending on the OS/Hardware and the JVM implementation. + * + * @param offsetInSeconds The offset in seconds from which the nanosecond + * time stamp should be computed. + * + * @apiNote The offset should be recent enough - so that + * {@code offsetInSeconds} is within {@code +/- 2^32} seconds of the + * current UTC time. If the offset is too far off, {@code -1} will be + * returned. As such, {@code -1} must not be considered as a valid + * nano time adjustment, but as an exception value indicating + * that an offset closer to the current time should be used. + * + * @return A nanosecond time stamp adjustment in the form of a single long. + * If the offset is too far off the current time, this method returns -1. + * In that case, the caller should call this method again, passing a + * more accurate offset. + */ + public static native long getNanoTimeAdjustment(long offsetInSeconds); + static { initialize(); } diff --git a/jdk/src/java.base/share/native/include/jvm.h b/jdk/src/java.base/share/native/include/jvm.h index 514378df9b2..7177f2e1d1e 100644 --- a/jdk/src/java.base/share/native/include/jvm.h +++ b/jdk/src/java.base/share/native/include/jvm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -104,6 +104,9 @@ JVM_CurrentTimeMillis(JNIEnv *env, jclass ignored); JNIEXPORT jlong JNICALL JVM_NanoTime(JNIEnv *env, jclass ignored); +JNIEXPORT jlong JNICALL +JVM_GetNanoTimeAdjustment(JNIEnv *env, jclass ignored, jlong offset_secs); + JNIEXPORT void JNICALL JVM_ArrayCopy(JNIEnv *env, jclass ignored, jobject src, jint src_pos, jobject dst, jint dst_pos, jint length); diff --git a/jdk/src/java.base/share/native/libjava/VM.c b/jdk/src/java.base/share/native/libjava/VM.c index 1968a06b01b..14fd1a63487 100644 --- a/jdk/src/java.base/share/native/libjava/VM.c +++ b/jdk/src/java.base/share/native/libjava/VM.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2015, 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 @@ -33,6 +33,11 @@ #include "sun_misc_VM.h" +/* Only register the performance-critical methods */ +static JNINativeMethod methods[] = { + {"getNanoTimeAdjustment", "(J)J", (void *)&JVM_GetNanoTimeAdjustment} +}; + JNIEXPORT jobject JNICALL Java_sun_misc_VM_latestUserDefinedLoader(JNIEnv *env, jclass cls) { return JVM_LatestUserDefinedLoader(env); @@ -49,6 +54,14 @@ Java_sun_misc_VM_initialize(JNIEnv *env, jclass cls) { return; } + // Registers implementations of native methods described in methods[] + // above. + // In particular, registers JVM_GetNanoTimeAdjustment as the implementation + // of the native sun.misc.VM.getNanoTimeAdjustment - avoiding the cost of + // introducing a Java_sun_misc_VM_getNanoTimeAdjustment wrapper + (*env)->RegisterNatives(env, cls, + methods, sizeof(methods)/sizeof(methods[0])); + func_p = (GetJvmVersionInfo_fp) JDK_FindJvmEntry("JVM_GetVersionInfo"); if (func_p != NULL) { jvm_version_info info; diff --git a/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java index 40ed5347589..51b1163dbca 100644 --- a/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -292,7 +292,8 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { expected = LocalDateTime.now(Clock.system(zone)); test = LocalDateTime.now(zone); } - assertEquals(test, expected); + assertEquals(test.truncatedTo(ChronoUnit.SECONDS), + expected.truncatedTo(ChronoUnit.SECONDS)); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKLocalTime.java b/jdk/test/java/time/tck/java/time/TCKLocalTime.java index f79e8fc41f6..88f99ca8c65 100644 --- a/jdk/test/java/time/tck/java/time/TCKLocalTime.java +++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -246,7 +246,8 @@ public class TCKLocalTime extends AbstractDateTimeTest { expected = LocalTime.now(Clock.system(zone)); test = LocalTime.now(zone); } - assertEquals(test, expected); + assertEquals(test.truncatedTo(ChronoUnit.SECONDS), + expected.truncatedTo(ChronoUnit.SECONDS)); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java index fb743e87b14..11ace2decf4 100644 --- a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -260,7 +260,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { expected = ZonedDateTime.now(Clock.system(zone)); test = ZonedDateTime.now(zone); } - assertEquals(test, expected); + assertEquals(test.truncatedTo(ChronoUnit.SECONDS), + expected.truncatedTo(ChronoUnit.SECONDS)); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/test/java/time/TestClock_System.java b/jdk/test/java/time/test/java/time/TestClock_System.java index 881a76060a1..527008920cc 100644 --- a/jdk/test/java/time/test/java/time/TestClock_System.java +++ b/jdk/test/java/time/test/java/time/TestClock_System.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -62,7 +62,9 @@ package test.java.time; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertSame; +import java.lang.reflect.Field; import java.time.Clock; +import java.time.Instant; import java.time.ZoneId; import org.testng.annotations.Test; @@ -87,4 +89,298 @@ public class TestClock_System { assertEquals(test.toString(), "SystemClock[Europe/Paris]"); } + //----------------------------------------------------------------------- + + private static String formatTime(String prefix, Instant time) { + return prefix + ": " + time + " - seconds: " + + time.getEpochSecond() + ", nanos: " + + time.getNano(); + } + + public void test_ClockResolution() { + Clock highestUTC = Clock.systemUTC(); + + Instant start = Instant.ofEpochMilli(System.currentTimeMillis()); + + try { + // smoke test + Instant system1 = Instant.ofEpochMilli(System.currentTimeMillis()); + Instant system2 = Instant.ofEpochMilli(System.currentTimeMillis()); + Instant highest1 = highestUTC.instant(); + Instant highest2 = highestUTC.instant(); + System.out.println(formatTime("\nsystemUTC #1 ", system1)); + System.out.println(formatTime("systemUTC #2 ", system2)); + System.out.println(formatTime("highestResolutionUTC #1 ", highest1)); + System.out.println(formatTime("highestResolutionUTC #2 ", highest2)); + + if (system2.isBefore(system1)) { + System.err.println("system2 is before system1!"); + System.err.println(formatTime("\n\tsystem1", system1)); + System.err.println(formatTime("\n\tsystem2", system2)); + throw new RuntimeException("system2 is before system1!" + + formatTime("\n\tsystem1", system1) + + formatTime("\n\tsystem2", system2)); + } + if (highest2.isBefore(highest1)) { + System.err.println("highest2 is before highest1!"); + System.err.println(formatTime("\n\thighest1", system1)); + System.err.println(formatTime("\n\tsystem2", highest2)); + throw new RuntimeException("highest2 is before system1!" + + formatTime("\n\thighest1", system1) + + formatTime("\n\tsystem2", highest2)); + } + + // better test - but depends on implementation details. + // we're not rounding - so highest1 should be greater or equal to + // system1 + system1 = Instant.ofEpochMilli(System.currentTimeMillis()); + highest1 = highestUTC.instant(); + + System.out.println(formatTime("\nsystemUTC ", system1)); + System.out.println(formatTime("highestResolutionUTC ", highest1)); + + if (highest1.isBefore(system1)) { + System.err.println("highest1 is before system1!"); + System.err.println(formatTime("\n\tsystem1", system1)); + System.err.println(formatTime("\n\thighest1", highest1)); + throw new RuntimeException("highest1 is before system1!" + + formatTime("\n\tsystem1", system1) + + formatTime("\n\thighest1", highest1)); + } + + int count=0; + // let's preheat the system a bit: + for (int i = 0; i < 1000 ; i++) { + system1 = Instant.ofEpochMilli(System.currentTimeMillis()); + highest1 = highestUTC.instant(); + final int sysnan = system1.getNano(); + final int nanos = highest1.getNano(); + if ((nanos % 1000000) > 0) { + count++; // we have micro seconds + } + if ((sysnan % 1000000) > 0) { + throw new RuntimeException("Expected only millisecconds " + + "precision for systemUTC, found " + + (sysnan % 1000000) + " remainder."); + } + } + System.out.println("\nNumber of time stamps which had better than" + + " millisecond precision: "+count+"/"+1000); + System.out.println(formatTime("\nsystemUTC ", system1)); + System.out.println(formatTime("highestResolutionUTC ", highest1)); + if (count == 0) { + System.err.println("Something is strange: no microsecond " + + "precision with highestResolutionUTC?"); + throw new RuntimeException("Micro second preccision not reached"); + } + + // check again + if (highest1.isBefore(system1)) { + System.err.println("highest1 is before system1!"); + System.err.println(formatTime("\n\tsystem1", system1)); + System.err.println(formatTime("\n\thighest1", highest1)); + throw new RuntimeException("highest1 is before system1!" + + formatTime("\n\tsystem1", system1) + + formatTime("\n\thighest1", highest1)); + } + + // leap of faith: ensure that highest1 is from within 10 secs of + // system1 + if (highest1.toEpochMilli() != system1.toEpochMilli()) { + long delta = highest1.getEpochSecond() - system1.getEpochSecond(); + if (delta > 10) { + throw new RuntimeException("Unexpected long delay between two clocks (" + + delta + " seconds)" + + formatTime("\n\t system1", system1) + + formatTime("\n\t highest1", highest1)); + + } + } else { + System.out.println("You won the lottery: the two dates are within 1 millisecond!\n"); + } + + } finally { + Instant stop = Instant.ofEpochMilli(System.currentTimeMillis()); + if (start.isAfter(stop)) { + // This should not happen - but can (un)probably be observed + // when switching to summer time, or if another application + // is switching the system date... + System.err.println("Cannot test - date was setback: " + + formatTime("\n\tstarted at", start) + + formatTime("\n\tstopped at", stop) + "\n"); + return; // will prevent exceptions from being propagated. + } + } + } + + static final long MAX_OFFSET = 0x0100000000L; + static final long MIN_OFFSET = -MAX_OFFSET; + + // A helper class to test that SystemClock correctly recomputes + // its offset. + static class SystemClockOffset { + + static final int MILLIS_IN_SECOND = 1000; + static final int NANOS_IN_MILLI = 1000_000; + static final int NANOS_IN_MICRO = 1000; + static final int NANOS_IN_SECOND = 1000_000_000; + + static final boolean verbose = true; + static final Clock systemUTC = Clock.systemUTC(); + static final Field offsetField; + + static { + try { + offsetField = Class.forName("java.time.Clock$SystemClock").getDeclaredField("offset"); + offsetField.setAccessible(true); + } catch (ClassNotFoundException | NoSuchFieldException ex) { + throw new ExceptionInInitializerError(ex); + } + } + + static enum Answer { + + YES, // isOffLimit = YES: we must get -1 + NO, // isOffLimit = NO: we must not not get -1 + MAYBE // isOffLimit = MAYBE: we might get -1 or a valid adjustment. + }; + + static long distance(long one, long two) { + return one > two ? Math.subtractExact(one, two) + : Math.subtractExact(two, one); + } + + static Answer isOffLimits(long before, long after, long offset) { + long relativeDistanceBefore = distance(before, offset); + long relativeDistanceAfter = distance(after, offset); + if (relativeDistanceBefore >= MAX_OFFSET && relativeDistanceAfter >= MAX_OFFSET) { + return Answer.YES; + } + if (relativeDistanceBefore < MAX_OFFSET && relativeDistanceAfter < MAX_OFFSET) { + if (relativeDistanceBefore == 0 || relativeDistanceAfter == 0) { + return Answer.MAYBE; // unlucky case where + } + return Answer.NO; + } + return Answer.MAYBE; + } + + static void testWithOffset(String name, long offset) + throws IllegalAccessException { + testWithOffset(name, offset, systemUTC); + } + + static void testWithOffset(String name, long offset, Clock clock) + throws IllegalAccessException { + offsetField.set(clock, offset); + long beforeMillis = System.currentTimeMillis(); + final Instant instant = clock.instant(); + long afterMillis = System.currentTimeMillis(); + long actualOffset = offsetField.getLong(clock); + long instantMillis = instant.getEpochSecond() * MILLIS_IN_SECOND + + instant.getNano() / NANOS_IN_MILLI; + if (instantMillis < beforeMillis || instantMillis > afterMillis) { + throw new RuntimeException(name + + ": Invalid instant: " + instant + + " (~" + instantMillis + "ms)" + + " when time in millis is in [" + + beforeMillis + ", " + afterMillis + + "] and offset in seconds is " + offset); + } + Answer isOffLimits = isOffLimits(beforeMillis / MILLIS_IN_SECOND, + afterMillis / MILLIS_IN_SECOND, offset); + switch (isOffLimits) { + case YES: + if (actualOffset == offset) { + throw new RuntimeException(name + + ": offset was offlimit but was not recomputed " + + " when time in millis is in [" + + beforeMillis + ", " + afterMillis + + "] and offset in seconds was " + offset); + } + break; + case NO: + if (actualOffset != offset) { + throw new RuntimeException(name + + ": offset was not offlimit but was recomputed."); + } + break; + default: + break; + } + if (distance(actualOffset, instant.getEpochSecond()) >= MAX_OFFSET) { + throw new RuntimeException(name + ": Actual offset is too far off:" + + " offset=" + actualOffset + + "instant.seconds=" + instant.getEpochSecond()); + } + long adjustment = (instant.getEpochSecond() - actualOffset) * NANOS_IN_SECOND + + instant.getNano(); + validateAdjustment(name, actualOffset, beforeMillis, afterMillis, adjustment); + } + + static void validateAdjustment(String name, long offset, long beforeMillis, + long afterMillis, long adjustment) { + System.out.println("Validating adjustment: " + adjustment); + long expectedMax = distance(offset, beforeMillis / MILLIS_IN_SECOND) + * NANOS_IN_SECOND + + (beforeMillis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + + (afterMillis - beforeMillis + 1) * NANOS_IN_MILLI; + long absoluteAdjustment = distance(0, adjustment); + if (absoluteAdjustment > expectedMax) { + long adjSec = absoluteAdjustment / NANOS_IN_SECOND; + long adjMil = (absoluteAdjustment % NANOS_IN_SECOND) / NANOS_IN_MILLI; + long adjMic = (absoluteAdjustment % NANOS_IN_MILLI) / NANOS_IN_MICRO; + long adjNan = (absoluteAdjustment % NANOS_IN_MICRO); + long expSec = expectedMax / NANOS_IN_SECOND; + long expMil = (expectedMax % NANOS_IN_SECOND) / NANOS_IN_MILLI; + long expMic = (expectedMax % NANOS_IN_MILLI) / NANOS_IN_MICRO; + long expNan = (expectedMax % NANOS_IN_MICRO); + System.err.println("Excessive adjustment: " + adjSec + "s, " + + adjMil + "ms, " + adjMic + "mics, " + adjNan + "ns"); + System.err.println("Epected max: " + expSec + "s, " + + expMil + "ms, " + expMic + "mics, " + expNan + "ns"); + + throw new RuntimeException(name + + ": Excessive adjustment: " + adjustment + + " when time in millis is in [" + + beforeMillis + ", " + afterMillis + + "] and offset in seconds is " + offset); + } + } + } + + public void test_OffsetRegular() throws IllegalAccessException { + System.out.println("*** Testing regular cases ***"); + SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000", + System.currentTimeMillis()/1000); + SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - 1024", + System.currentTimeMillis()/1000 - 1024); + SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 + 1024", + System.currentTimeMillis()/1000 + 1024); + } + + public void test_OffsetLimits() throws IllegalAccessException { + System.out.println("*** Testing limits ***"); + SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET + 1", + System.currentTimeMillis()/1000 - MAX_OFFSET + 1); + SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET - 1", + System.currentTimeMillis()/1000 + MAX_OFFSET - 1); + SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET", + System.currentTimeMillis()/1000 - MAX_OFFSET); + SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET", + System.currentTimeMillis()/1000 + MAX_OFFSET); + SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET - 1024", + System.currentTimeMillis()/1000 - MAX_OFFSET - 1024); + SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET + 1024", + System.currentTimeMillis()/1000 + MAX_OFFSET + 1024); + SystemClockOffset.testWithOffset("0", 0); + SystemClockOffset.testWithOffset("-1", -1); + SystemClockOffset.testWithOffset("Integer.MAX_VALUE + System.currentTimeMillis()/1000", + ((long)Integer.MAX_VALUE) + System.currentTimeMillis()/1000); + SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - Integer.MIN_VALUE", + System.currentTimeMillis()/1000 - Integer.MIN_VALUE); + SystemClockOffset.testWithOffset("Long.MAX_VALUE", Long.MAX_VALUE); + SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - Long.MIN_VALUE", + (Long.MIN_VALUE + System.currentTimeMillis()/1000)*-1); + } } diff --git a/jdk/test/java/time/test/java/util/TestFormatter.java b/jdk/test/java/time/test/java/util/TestFormatter.java index 67a73cee697..5cf2163412c 100644 --- a/jdk/test/java/time/test/java/util/TestFormatter.java +++ b/jdk/test/java/time/test/java/util/TestFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, 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 @@ -38,6 +38,7 @@ import java.time.chrono.Chronology; import java.time.temporal.ChronoField; import java.time.temporal.TemporalQueries; import java.time.temporal.TemporalAccessor; +import java.time.temporal.UnsupportedTemporalTypeException; import java.util.*; @@ -153,6 +154,44 @@ public class TestFormatter { if (verbose) { System.out.printf("%-24s : %s%n", getClassName(dt), out); } + + // expected usually comes from Calendar which only has milliseconds + // precision. So we're going to replace it's N:[nanos] stamp with + // the correct value for nanos. + if ((dt instanceof TemporalAccessor) && expected != null) { + try { + // Get millis & nanos from the dt + final TemporalAccessor ta = (TemporalAccessor) dt; + final int nanos = ta.get(ChronoField.NANO_OF_SECOND); + final int millis = ta.get(ChronoField.MILLI_OF_SECOND); + final String nanstr = String.valueOf(nanos); + final String mistr = String.valueOf(millis); + + // Compute the value of the N:[nanos] field that we expect + // to find in 'out' + final StringBuilder sb = new StringBuilder(); + sb.append("N:["); + for (int i=nanstr.length(); i<9; i++) { + sb.append('0'); + } + sb.append(nanos).append("]"); + + // Compute the truncated value of N:[nanos] field that might + // be in 'expected' when expected was built from Calendar. + final StringBuilder sbm = new StringBuilder(); + sbm.append("N:["); + for (int i=mistr.length(); i<3; i++) { + sbm.append('0'); + } + sbm.append(mistr).append("000000]"); + + // if expected contains the truncated value, replace it with + // the complete value. + expected = expected.replace(sbm.toString(), sb.toString()); + } catch (UnsupportedTemporalTypeException e) { + // nano seconds unsupported - nothing to do... + } + } if (expected != null && !out.equals(expected)) { System.out.printf("%-24s actual: %s%n FAILED; expected: %s%n", getClassName(dt), out, expected); diff --git a/jdk/test/sun/misc/VM/GetNanoTimeAdjustment.java b/jdk/test/sun/misc/VM/GetNanoTimeAdjustment.java new file mode 100644 index 00000000000..bfeb8c0c7f3 --- /dev/null +++ b/jdk/test/sun/misc/VM/GetNanoTimeAdjustment.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2015, 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. + */ +import java.util.Objects; +import sun.misc.VM; + +/** + * @test + * @bug 8068730 + * @summary tests that VM.getgetNanoTimeAdjustment() works as expected. + * @run main GetNanoTimeAdjustment + * @author danielfuchs + */ +public class GetNanoTimeAdjustment { + + static final int MILLIS_IN_SECOND = 1000; + static final int NANOS_IN_MILLI = 1000_000; + static final int NANOS_IN_MICRO = 1000; + static final int NANOS_IN_SECOND = 1000_000_000; + + static final boolean verbose = true; + + static final class TestAssertException extends RuntimeException { + TestAssertException(String msg) { super(msg); } + } + + private static void assertEquals(long expected, long received, String msg) { + if (expected != received) { + throw new TestAssertException("Unexpected result for " + msg + + ".\n\texpected: " + expected + + "\n\tactual: " + received); + } else if (verbose) { + System.out.println("Got expected " + msg + ": " + received); + } + } + + private static void assertEquals(Object expected, Object received, String msg) { + if (!Objects.equals(expected, received)) { + throw new TestAssertException("Unexpected result for " + msg + + ".\n\texpected: " + expected + + "\n\tactual: " + received); + } else if (verbose) { + System.out.println("Got expected " + msg + ": " + received); + } + } + + static final long MAX_OFFSET = 0x0100000000L; + static final long MIN_OFFSET = -MAX_OFFSET; + static enum Answer { + YES, // isOffLimit = YES: we must get -1 + NO, // isOffLimit = NO: we must not not get -1 + MAYBE // isOffLimit = MAYBE: we might get -1 or a valid adjustment. + }; + static long distance(long one, long two) { + return one > two ? Math.subtractExact(one, two) + : Math.subtractExact(two, one); + } + + + static Answer isOffLimits(long before, long after, long offset) { + long relativeDistanceBefore = distance(before, offset); + long relativeDistanceAfter = distance(after, offset); + if (relativeDistanceBefore >= MAX_OFFSET && relativeDistanceAfter >= MAX_OFFSET) { + return Answer.YES; + } + if (relativeDistanceBefore < MAX_OFFSET && relativeDistanceAfter < MAX_OFFSET) { + if (relativeDistanceBefore == 0 || relativeDistanceAfter == 0) { + return Answer.MAYBE; // unlucky case where + } + return Answer.NO; + } + return Answer.MAYBE; + } + + static void testWithOffset(String name, long offset) { + System.out.println("Testing with offset: " + name); + long beforeMillis = System.currentTimeMillis(); + long adjustment = VM.getNanoTimeAdjustment(offset); + long afterMillis = System.currentTimeMillis(); + + if (offset >= beforeMillis/MILLIS_IN_SECOND + && offset <= afterMillis/MILLIS_IN_SECOND) { + if (adjustment == -1) { + // it's possible that we have fallen in the unlucky case + // where -1 was the genuine result. let's go backward a bit. + offset = offset - 10; + beforeMillis = System.currentTimeMillis(); + adjustment = VM.getNanoTimeAdjustment(offset); + afterMillis = System.currentTimeMillis(); + if (adjustment == -1) { + throw new RuntimeException(name + ": VM says " + offset + + " secs is too far off, " + + " when time in seconds is in [" + + beforeMillis/MILLIS_IN_SECOND + ", " + + afterMillis/MILLIS_IN_SECOND + + "]"); + } + } + } + + Answer isOffLimit = isOffLimits(beforeMillis/MILLIS_IN_SECOND, + afterMillis/MILLIS_IN_SECOND, offset); + switch (isOffLimit) { + case YES: + if (adjustment != -1) { + throw new RuntimeException(name + + ": VM should have returned -1 for " + + offset + + " when time in seconds is in [" + + beforeMillis/MILLIS_IN_SECOND + ", " + + afterMillis/MILLIS_IN_SECOND + "]"); + } + System.out.println("Got expected exception value: " + adjustment); + break; + case NO: + if (adjustment == -1) { + throw new RuntimeException(name + + "VM says " + offset + + " secs is too far off, " + + " when time in seconds is in [" + + beforeMillis/MILLIS_IN_SECOND + ", " + + afterMillis/MILLIS_IN_SECOND + + "]"); + } + break; + case MAYBE: + System.out.println("Adjustment: " + adjustment); + System.out.println("Can't assert for -1 with offset " + + offset + "(" + name + ")" + + " when time in seconds is in [" + + beforeMillis/MILLIS_IN_SECOND + ", " + + afterMillis/MILLIS_IN_SECOND + + "]"); + // not conclusive + } + + if (isOffLimit == Answer.NO || adjustment != -1) { + System.out.println("Validating adjustment: " + adjustment); + long expectedMax = distance(offset, beforeMillis/MILLIS_IN_SECOND) + * NANOS_IN_SECOND + + (beforeMillis % MILLIS_IN_SECOND) * NANOS_IN_MILLI + + (afterMillis - beforeMillis + 1) * NANOS_IN_MILLI; + long absoluteAdjustment = distance(0, adjustment); + if (absoluteAdjustment > expectedMax) { + long adjSec = absoluteAdjustment / NANOS_IN_SECOND; + long adjMil = (absoluteAdjustment % NANOS_IN_SECOND) / NANOS_IN_MILLI; + long adjMic = (absoluteAdjustment % NANOS_IN_MILLI) / NANOS_IN_MICRO; + long adjNan = (absoluteAdjustment % NANOS_IN_MICRO); + long expSec = expectedMax / NANOS_IN_SECOND; + long expMil = (expectedMax % NANOS_IN_SECOND) / NANOS_IN_MILLI; + long expMic = (expectedMax % NANOS_IN_MILLI) / NANOS_IN_MICRO; + long expNan = (expectedMax % NANOS_IN_MICRO); + System.err.println("Excessive adjustment: " + adjSec + "s, " + + adjMil + "ms, " + adjMic + "mics, " + adjNan + "ns"); + System.err.println("Epected max: " + expSec + "s, " + + expMil + "ms, " + expMic + "mics, " + expNan + "ns"); + + throw new RuntimeException(name + + ": Excessive adjustment: " + adjustment + + " when time in millis is in [" + + beforeMillis + ", " + afterMillis + + "] and offset in seconds is " + offset); + } + } + + } + + static void regular() { + System.out.println("*** Testing regular cases ***"); + final long start = System.currentTimeMillis(); + long offset = start/1000; + long adjustment = VM.getNanoTimeAdjustment(offset); + if (start != offset*1000) { + if (adjustment == -1) { + throw new RuntimeException("VM says " + offset + + " secs is too far off, but time millis is " + + System.currentTimeMillis()); + } + } + if (adjustment == -1) { + offset = System.currentTimeMillis()/1000 - 1024; + adjustment = VM.getNanoTimeAdjustment(offset); + if (adjustment == -1) { + throw new RuntimeException("VM says " + offset + + " secs is too far off, but time millis is " + + System.currentTimeMillis()); + } + } + if (adjustment > (start/1000 - offset + 20)*NANOS_IN_SECOND) { + throw new RuntimeException("Excessive adjustment: " + adjustment); + } + testWithOffset("System.currentTimeMillis()/1000", + System.currentTimeMillis()/1000); + testWithOffset("System.currentTimeMillis()/1000 - 1024", + System.currentTimeMillis()/1000 - 1024); + testWithOffset("System.currentTimeMillis()/1000 + 1024", + System.currentTimeMillis()/1000 + 1024); + } + + static void testLimits() { + System.out.println("*** Testing limits ***"); + testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET + 1", + System.currentTimeMillis()/1000 - MAX_OFFSET + 1); + testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET - 1", + System.currentTimeMillis()/1000 + MAX_OFFSET - 1); + testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET", + System.currentTimeMillis()/1000 - MAX_OFFSET); + testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET", + System.currentTimeMillis()/1000 + MAX_OFFSET); + testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET - 1024", + System.currentTimeMillis()/1000 - MAX_OFFSET - 1024); + testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET + 1024", + System.currentTimeMillis()/1000 + MAX_OFFSET + 1024); + testWithOffset("0", 0); + testWithOffset("-1", -1); + testWithOffset("Integer.MAX_VALUE + System.currentTimeMillis()/1000", + ((long)Integer.MAX_VALUE) + System.currentTimeMillis()/1000); + testWithOffset("System.currentTimeMillis()/1000 - Integer.MIN_VALUE", + System.currentTimeMillis()/1000 - Integer.MIN_VALUE); + testWithOffset("Long.MAX_VALUE", Long.MAX_VALUE); + testWithOffset("System.currentTimeMillis()/1000 - Long.MIN_VALUE", + (Long.MIN_VALUE + System.currentTimeMillis()/1000)*-1); + } + + public static void main(String[] args) throws Exception { + regular(); + testLimits(); + } + +} From d09ec5b3e139889eb3caae37bf766cf58cca6d39 Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Wed, 28 Jan 2015 17:58:08 +0100 Subject: [PATCH 51/72] 8067139: Finally blocks inlined incorrectly Reviewed-by: hannesw, lagergren --- .../internal/codegen/AssignSymbols.java | 4 +- .../internal/codegen/CodeGenerator.java | 38 +++- .../codegen/CodeGeneratorLexicalContext.java | 4 +- .../codegen/LocalVariableTypesCalculator.java | 28 ++- .../jdk/nashorn/internal/codegen/Lower.java | 174 +++++++++++------- .../internal/codegen/SplitIntoFunctions.java | 6 + .../nashorn/internal/codegen/WeighNodes.java | 7 + .../jdk/nashorn/internal/ir/Block.java | 8 + .../internal/ir/BlockLexicalContext.java | 2 +- .../nashorn/internal/ir/BlockStatement.java | 9 + .../jdk/nashorn/internal/ir/BreakNode.java | 2 +- .../jdk/nashorn/internal/ir/ContinueNode.java | 2 +- .../nashorn/internal/ir/JumpStatement.java | 21 ++- .../internal/ir/JumpToInlinedFinally.java | 90 +++++++++ .../nashorn/internal/ir/LexicalContext.java | 42 ++++- .../internal/ir/LexicalContextNode.java | 4 +- .../internal/ir/OptimisticLexicalContext.java | 2 +- .../jdk/nashorn/internal/ir/TryNode.java | 147 +++++++++++---- .../internal/ir/debug/PrintVisitor.java | 3 + .../internal/ir/visitor/NodeVisitor.java | 21 +++ nashorn/test/script/basic/JDK-8067139.js | 92 +++++++++ 21 files changed, 568 insertions(+), 138 deletions(-) create mode 100644 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpToInlinedFinally.java create mode 100644 nashorn/test/script/basic/JDK-8067139.js diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java index f860886054b..1b85e94cb05 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java @@ -926,9 +926,7 @@ final class AssignSymbols extends NodeVisitor implements Loggabl @Override public Node leaveTryNode(final TryNode tryNode) { tryNode.setException(exceptionSymbol()); - if (tryNode.getFinallyBody() != null) { - tryNode.setFinallyCatchAll(exceptionSymbol()); - } + assert tryNode.getFinallyBody() == null; end(tryNode); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java index b4ccca17b11..d285541ffcf 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -85,7 +85,6 @@ import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.Block; import jdk.nashorn.internal.ir.BlockStatement; import jdk.nashorn.internal.ir.BreakNode; -import jdk.nashorn.internal.ir.BreakableNode; import jdk.nashorn.internal.ir.CallNode; import jdk.nashorn.internal.ir.CaseNode; import jdk.nashorn.internal.ir.CatchNode; @@ -102,6 +101,7 @@ import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; import jdk.nashorn.internal.ir.JoinPredecessorExpression; import jdk.nashorn.internal.ir.JumpStatement; +import jdk.nashorn.internal.ir.JumpToInlinedFinally; import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LexicalContextNode; @@ -1110,7 +1110,14 @@ final class CodeGenerator extends NodeOperatorVisitor T pop(final T node) { + public T pop(final T node) { final T popped = super.pop(node); if (isWithBoundary(node)) { dynamicScopeCount--; diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java index 28cc55104b1..79e151b0b88 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java @@ -62,6 +62,7 @@ import jdk.nashorn.internal.ir.IndexNode; import jdk.nashorn.internal.ir.JoinPredecessor; import jdk.nashorn.internal.ir.JoinPredecessorExpression; import jdk.nashorn.internal.ir.JumpStatement; +import jdk.nashorn.internal.ir.JumpToInlinedFinally; import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LexicalContextNode; @@ -529,8 +530,7 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ return false; } assertTypeStackIsEmpty(); - final BreakableNode target = jump.getTarget(lc); - jumpToLabel(jump, jump.getTargetLabel(target), getBreakTargetTypes(target)); + jumpToLabel(jump, jump.getTargetLabel(lc), getBreakTargetTypes(jump.getPopScopeLimit(lc))); doesNotContinueSequentially(); return false; } @@ -783,6 +783,11 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ return false; } + @Override + public boolean enterJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) { + return enterJumpStatement(jumpToInlinedFinally); + } + @Override public boolean enterLiteralNode(final LiteralNode literalNode) { if (literalNode instanceof ArrayLiteralNode) { @@ -1042,6 +1047,17 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ } doesNotContinueSequentially(); + for (final Block inlinedFinally : tryNode.getInlinedFinallies()) { + final Block finallyBody = TryNode.getLabelledInlinedFinallyBlock(inlinedFinally); + joinOnLabel(finallyBody.getEntryLabel()); + // NOTE: the jump to inlined finally can end up in dead code, so it is not necessarily reachable. + if (reachable) { + finallyBody.accept(this); + // All inlined finallies end with a jump or a return + assert !reachable; + } + } + joinOnLabel(catchLabel); for(final CatchNode catchNode: tryNode.getCatches()) { final IdentNode exception = catchNode.getException(); @@ -1125,7 +1141,7 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ return false; }; - private Map getBreakTargetTypes(final BreakableNode target) { + private Map getBreakTargetTypes(final LexicalContextNode target) { // Remove symbols defined in the the blocks that are being broken out of. Map types = localVariableTypes; for(final Iterator it = lc.getAllNodes(); it.hasNext();) { @@ -1380,7 +1396,11 @@ final class LocalVariableTypesCalculator extends NodeVisitor{ if(node instanceof JoinPredecessor) { final JoinPredecessor original = joinPredecessors.pop(); assert original.getClass() == node.getClass() : original.getClass().getName() + "!=" + node.getClass().getName(); - return (Node)setLocalVariableConversion(original, (JoinPredecessor)node); + final JoinPredecessor newNode = setLocalVariableConversion(original, (JoinPredecessor)node); + if (newNode instanceof LexicalContextNode) { + lc.replace((LexicalContextNode)node, (LexicalContextNode)newNode); + } + return (Node)newNode; } return node; } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java index a30e79a49d4..8bb947cd346 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java @@ -56,9 +56,11 @@ import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; import jdk.nashorn.internal.ir.JumpStatement; +import jdk.nashorn.internal.ir.JumpToInlinedFinally; import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; +import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode; import jdk.nashorn.internal.ir.LoopNode; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ReturnNode; @@ -115,7 +117,7 @@ final class Lower extends NodeOperatorVisitor implements Lo for (final Statement statement : statements) { if (!terminated) { newStatements.add(statement); - if (statement.isTerminal() || statement instanceof BreakNode || statement instanceof ContinueNode) { //TODO hasGoto? But some Loops are hasGoto too - why? + if (statement.isTerminal() || statement instanceof JumpStatement) { //TODO hasGoto? But some Loops are hasGoto too - why? terminated = true; } } else { @@ -182,6 +184,12 @@ final class Lower extends NodeOperatorVisitor implements Lo return false; } + @Override + public boolean enterJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) { + addStatement(jumpToInlinedFinally); + return false; + } + @Override public boolean enterEmptyNode(final EmptyNode emptyNode) { return false; @@ -318,8 +326,8 @@ final class Lower extends NodeOperatorVisitor implements Lo return addStatement(throwNode); //ThrowNodes are always terminal, marked as such in constructor } - private static Node ensureUniqueNamesIn(final Node node) { - return node.accept(new NodeVisitor(new LexicalContext()) { + private static T ensureUniqueNamesIn(final T node) { + return (T)node.accept(new NodeVisitor(new LexicalContext()) { @Override public Node leaveFunctionNode(final FunctionNode functionNode) { final String name = functionNode.getName(); @@ -333,15 +341,15 @@ final class Lower extends NodeOperatorVisitor implements Lo }); } - private static List copyFinally(final Block finallyBody) { + private static Block createFinallyBlock(final Block finallyBody) { final List newStatements = new ArrayList<>(); for (final Statement statement : finallyBody.getStatements()) { - newStatements.add((Statement)ensureUniqueNamesIn(statement)); + newStatements.add(statement); if (statement.hasTerminalFlags()) { - return newStatements; + break; } } - return newStatements; + return finallyBody.setStatements(null, newStatements); } private Block catchAllBlock(final TryNode tryNode) { @@ -367,28 +375,24 @@ final class Lower extends NodeOperatorVisitor implements Lo return new IdentNode(functionNode.getToken(), functionNode.getFinish(), cc.symbolName()); } - private static boolean isTerminal(final List statements) { - return !statements.isEmpty() && statements.get(statements.size() - 1).hasTerminalFlags(); + private static boolean isTerminalFinally(final Block finallyBlock) { + return finallyBlock.getLastStatement().hasTerminalFlags(); } /** * Splice finally code into all endpoints of a trynode * @param tryNode the try node - * @param rethrows list of rethrowing throw nodes from synthetic catch blocks + * @param rethrow the rethrowing throw nodes from the synthetic catch block * @param finallyBody the code in the original finally block * @return new try node after splicing finally code (same if nop) */ - private Node spliceFinally(final TryNode tryNode, final List rethrows, final Block finallyBody) { + private TryNode spliceFinally(final TryNode tryNode, final ThrowNode rethrow, final Block finallyBody) { assert tryNode.getFinallyBody() == null; + final Block finallyBlock = createFinallyBlock(finallyBody); + final ArrayList inlinedFinallies = new ArrayList<>(); + final FunctionNode fn = lc.getCurrentFunction(); final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor(new LexicalContext()) { - final List insideTry = new ArrayList<>(); - - @Override - public boolean enterDefault(final Node node) { - insideTry.add(node); - return true; - } @Override public boolean enterFunctionNode(final FunctionNode functionNode) { @@ -398,12 +402,8 @@ final class Lower extends NodeOperatorVisitor implements Lo @Override public Node leaveThrowNode(final ThrowNode throwNode) { - if (rethrows.contains(throwNode)) { - final List newStatements = copyFinally(finallyBody); - if (!isTerminal(newStatements)) { - newStatements.add(throwNode); - } - return BlockStatement.createReplacement(throwNode, newStatements); + if (rethrow == throwNode) { + return new BlockStatement(prependFinally(finallyBlock, throwNode)); } return throwNode; } @@ -419,58 +419,94 @@ final class Lower extends NodeOperatorVisitor implements Lo } private Node leaveJumpStatement(final JumpStatement jump) { - return copy(jump, (Node)jump.getTarget(Lower.this.lc)); + // NOTE: leaveJumpToInlinedFinally deliberately does not delegate to this method, only break and + // continue are edited. JTIF nodes should not be changed, rather the surroundings of + // break/continue/return that were moved into the inlined finally block itself will be changed. + + // If this visitor's lc doesn't find the target of the jump, it means it's external to the try block. + if (jump.getTarget(lc) == null) { + return createJumpToInlinedFinally(fn, inlinedFinallies, prependFinally(finallyBlock, jump)); + } + return jump; } @Override public Node leaveReturnNode(final ReturnNode returnNode) { - final Expression expr = returnNode.getExpression(); - final List newStatements = new ArrayList<>(); - - final Expression resultNode; - if (expr != null) { - //we need to evaluate the result of the return in case it is complex while - //still in the try block, store it in a result value and return it afterwards - resultNode = new IdentNode(Lower.this.compilerConstant(RETURN)); - newStatements.add(new ExpressionStatement(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr))); - } else { - resultNode = null; - } - - newStatements.addAll(copyFinally(finallyBody)); - if (!isTerminal(newStatements)) { - newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode)); - } - - return BlockStatement.createReplacement(returnNode, lc.getCurrentBlock().getFinish(), newStatements); - } - - private Node copy(final Statement endpoint, final Node targetNode) { - if (!insideTry.contains(targetNode)) { - final List newStatements = copyFinally(finallyBody); - if (!isTerminal(newStatements)) { - newStatements.add(endpoint); + final Expression expr = returnNode.getExpression(); + if (isTerminalFinally(finallyBlock)) { + if (expr == null) { + // Terminal finally; no return expression. + return createJumpToInlinedFinally(fn, inlinedFinallies, ensureUniqueNamesIn(finallyBlock)); } - return BlockStatement.createReplacement(endpoint, tryNode.getFinish(), newStatements); + // Terminal finally; has a return expression. + final List newStatements = new ArrayList<>(2); + final int retLineNumber = returnNode.getLineNumber(); + final long retToken = returnNode.getToken(); + // Expression is evaluated for side effects. + newStatements.add(new ExpressionStatement(retLineNumber, retToken, returnNode.getFinish(), expr)); + newStatements.add(createJumpToInlinedFinally(fn, inlinedFinallies, ensureUniqueNamesIn(finallyBlock))); + return new BlockStatement(retLineNumber, new Block(retToken, finallyBlock.getFinish(), newStatements)); + } else if (expr == null || expr instanceof PrimitiveLiteralNode || (expr instanceof IdentNode && RETURN.symbolName().equals(((IdentNode)expr).getName()))) { + // Nonterminal finally; no return expression, or returns a primitive literal, or returns :return. + // Just move the return expression into the finally block. + return createJumpToInlinedFinally(fn, inlinedFinallies, prependFinally(finallyBlock, returnNode)); + } else { + // We need to evaluate the result of the return in case it is complex while still in the try block, + // store it in :return, and return it afterwards. + final List newStatements = new ArrayList<>(); + final int retLineNumber = returnNode.getLineNumber(); + final long retToken = returnNode.getToken(); + final int retFinish = returnNode.getFinish(); + final Expression resultNode = new IdentNode(expr.getToken(), expr.getFinish(), RETURN.symbolName()); + // ":return = ;" + newStatements.add(new ExpressionStatement(retLineNumber, retToken, retFinish, new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr))); + // inline finally and end it with "return :return;" + newStatements.add(createJumpToInlinedFinally(fn, inlinedFinallies, prependFinally(finallyBlock, returnNode.setExpression(resultNode)))); + return new BlockStatement(retLineNumber, new Block(retToken, retFinish, newStatements)); } - return endpoint; } }); - - addStatement(newTryNode); - for (final Node statement : finallyBody.getStatements()) { - addStatement((Statement)statement); - } + addStatement(inlinedFinallies.isEmpty() ? newTryNode : newTryNode.setInlinedFinallies(lc, inlinedFinallies)); + // TODO: if finallyStatement is terminal, we could just have sites of inlined finallies jump here. + addStatement(new BlockStatement(finallyBlock)); return newTryNode; } + private static JumpToInlinedFinally createJumpToInlinedFinally(final FunctionNode fn, final List inlinedFinallies, final Block finallyBlock) { + final String labelName = fn.uniqueName(":finally"); + final long token = finallyBlock.getToken(); + final int finish = finallyBlock.getFinish(); + inlinedFinallies.add(new Block(token, finish, new LabelNode(finallyBlock.getFirstStatementLineNumber(), + token, finish, labelName, finallyBlock))); + return new JumpToInlinedFinally(labelName); + } + + private static Block prependFinally(final Block finallyBlock, final Statement statement) { + final Block inlinedFinally = ensureUniqueNamesIn(finallyBlock); + if (isTerminalFinally(finallyBlock)) { + return inlinedFinally; + } + final List stmts = inlinedFinally.getStatements(); + final List newStmts = new ArrayList<>(stmts.size() + 1); + newStmts.addAll(stmts); + newStmts.add(statement); + return new Block(inlinedFinally.getToken(), statement.getFinish(), newStmts); + } + @Override public Node leaveTryNode(final TryNode tryNode) { final Block finallyBody = tryNode.getFinallyBody(); + TryNode newTryNode = tryNode.setFinallyBody(lc, null); - if (finallyBody == null) { - return addStatement(ensureUnconditionalCatch(tryNode)); + // No finally or empty finally + if (finallyBody == null || finallyBody.getStatementCount() == 0) { + final List catches = newTryNode.getCatches(); + if (catches == null || catches.isEmpty()) { + // A completely degenerate try block: empty finally, no catches. Replace it with try body. + return addStatement(new BlockStatement(tryNode.getBody())); + } + return addStatement(ensureUnconditionalCatch(newTryNode)); } /* @@ -496,11 +532,9 @@ final class Lower extends NodeOperatorVisitor implements Lo * now splice in finally code wherever needed * */ - TryNode newTryNode; - final Block catchAll = catchAllBlock(tryNode); - final List rethrows = new ArrayList<>(); + final List rethrows = new ArrayList<>(1); catchAll.accept(new NodeVisitor(new LexicalContext()) { @Override public boolean enterThrowNode(final ThrowNode throwNode) { @@ -510,20 +544,18 @@ final class Lower extends NodeOperatorVisitor implements Lo }); assert rethrows.size() == 1; - if (tryNode.getCatchBlocks().isEmpty()) { - newTryNode = tryNode.setFinallyBody(null); - } else { - final Block outerBody = new Block(tryNode.getToken(), tryNode.getFinish(), ensureUnconditionalCatch(tryNode.setFinallyBody(null))); - newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null); + if (!tryNode.getCatchBlocks().isEmpty()) { + final Block outerBody = new Block(newTryNode.getToken(), newTryNode.getFinish(), ensureUnconditionalCatch(newTryNode)); + newTryNode = newTryNode.setBody(lc, outerBody).setCatchBlocks(lc, null); } - newTryNode = newTryNode.setCatchBlocks(Arrays.asList(catchAll)).setFinallyBody(null); + newTryNode = newTryNode.setCatchBlocks(lc, Arrays.asList(catchAll)); /* * Now that the transform is done, we have to go into the try and splice * the finally block in front of any statement that is outside the try */ - return spliceFinally(newTryNode, rethrows, finallyBody); + return (TryNode)lc.replace(tryNode, spliceFinally(newTryNode, rethrows.get(0), finallyBody)); } private TryNode ensureUnconditionalCatch(final TryNode tryNode) { @@ -535,7 +567,7 @@ final class Lower extends NodeOperatorVisitor implements Lo final List newCatchBlocks = new ArrayList<>(tryNode.getCatchBlocks()); newCatchBlocks.add(catchAllBlock(tryNode)); - return tryNode.setCatchBlocks(newCatchBlocks); + return tryNode.setCatchBlocks(lc, newCatchBlocks); } @Override diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java index 9b980b5d4c9..6fc6e3a9977 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java @@ -52,6 +52,7 @@ import jdk.nashorn.internal.ir.GetSplitState; import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.JumpStatement; +import jdk.nashorn.internal.ir.JumpToInlinedFinally; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ReturnNode; @@ -359,6 +360,11 @@ final class SplitIntoFunctions extends NodeVisitor { return leaveJumpNode(continueNode); } + @Override + public Node leaveJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) { + return leaveJumpNode(jumpToInlinedFinally); + } + private JumpStatement leaveJumpNode(final JumpStatement jump) { if (inSplitNode()) { final SplitState splitState = getCurrentSplitState(); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java index 26660a3a859..b1181c82843 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java @@ -40,6 +40,7 @@ import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; +import jdk.nashorn.internal.ir.JumpToInlinedFinally; import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; @@ -197,6 +198,12 @@ final class WeighNodes extends NodeOperatorVisitor { return indexNode; } + @Override + public Node leaveJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) { + weight += BREAK_WEIGHT; + return jumpToInlinedFinally; + } + @SuppressWarnings("rawtypes") @Override public boolean enterLiteralNode(final LiteralNode literalNode) { diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java index 7666041094d..c68dba2b014 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java @@ -321,6 +321,14 @@ public class Block extends Node implements BreakableNode, Terminal, Flags return statements.get(0).getLineNumber(); } + /** + * Returns the last statement in the block. + * @return the last statement in the block, or null if the block has no statements. + */ + public Statement getLastStatement() { + return statements.isEmpty() ? null : statements.get(statements.size() - 1); + } + /** * Reset the statement list for this block * diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockLexicalContext.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockLexicalContext.java index 7e16b5e6abc..0deb25f3e24 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockLexicalContext.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockLexicalContext.java @@ -74,7 +74,7 @@ public class BlockLexicalContext extends LexicalContext { @SuppressWarnings("unchecked") @Override - public T pop(final T node) { + public T pop(final T node) { T expected = node; if (node instanceof Block) { final List newStatements = popStatements(); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockStatement.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockStatement.java index 6f6a1d23873..3a7c8109682 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockStatement.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockStatement.java @@ -37,6 +37,15 @@ public class BlockStatement extends Statement { /** Block to execute. */ private final Block block; + /** + * Constructor + * + * @param block the block to execute + */ + public BlockStatement(final Block block) { + this(block.getFirstStatementLineNumber(), block); + } + /** * Constructor * diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BreakNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BreakNode.java index 4cbf4c02b26..3e80bccd370 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BreakNode.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BreakNode.java @@ -77,7 +77,7 @@ public final class BreakNode extends JumpStatement { } @Override - public Label getTargetLabel(final BreakableNode target) { + Label getTargetLabel(final BreakableNode target) { return target.getBreakLabel(); } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ContinueNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ContinueNode.java index c58531bdee1..eb67f412608 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ContinueNode.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ContinueNode.java @@ -78,7 +78,7 @@ public class ContinueNode extends JumpStatement { } @Override - public Label getTargetLabel(final BreakableNode target) { + Label getTargetLabel(final BreakableNode target) { return ((LoopNode)target).getContinueLabel(); } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpStatement.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpStatement.java index 07707171c63..628bc772d09 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpStatement.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpStatement.java @@ -101,7 +101,26 @@ public abstract class JumpStatement extends Statement implements JoinPredecessor * @throws ClassCastException if invoked on the kind of breakable node that this jump statement is not prepared to * handle. */ - public abstract Label getTargetLabel(final BreakableNode target); + abstract Label getTargetLabel(final BreakableNode target); + + /** + * Returns the label this jump statement targets. + * @param lc the lexical context + * @return the label this jump statement targets. + */ + public Label getTargetLabel(final LexicalContext lc) { + return getTargetLabel(getTarget(lc)); + } + + /** + * Returns the limit node for popping scopes when this jump statement is effected. + * @param lc the current lexical context + * @return the limit node for popping scopes when this jump statement is effected. + */ + public LexicalContextNode getPopScopeLimit(final LexicalContext lc) { + // In most cases (break and continue) this is equal to the target. + return getTarget(lc); + } @Override public JumpStatement setLocalVariableConversion(final LexicalContext lc, final LocalVariableConversion conversion) { diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpToInlinedFinally.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpToInlinedFinally.java new file mode 100644 index 00000000000..bba0d99e02e --- /dev/null +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpToInlinedFinally.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.internal.ir; + +import java.util.Objects; +import jdk.nashorn.internal.codegen.Label; +import jdk.nashorn.internal.ir.annotations.Immutable; +import jdk.nashorn.internal.ir.visitor.NodeVisitor; + +/** + * IR representation for synthetic jump into an inlined finally statement. + */ +@Immutable +public final class JumpToInlinedFinally extends JumpStatement { + private static final long serialVersionUID = 1L; + + /** + * Constructor + * + * @param labelName label name for inlined finally block + */ + public JumpToInlinedFinally(final String labelName) { + super(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH, Objects.requireNonNull(labelName)); + } + + private JumpToInlinedFinally(final JumpToInlinedFinally breakNode, final LocalVariableConversion conversion) { + super(breakNode, conversion); + } + + @Override + public Node accept(final NodeVisitor visitor) { + if (visitor.enterJumpToInlinedFinally(this)) { + return visitor.leaveJumpToInlinedFinally(this); + } + + return this; + } + + @Override + JumpStatement createNewJumpStatement(final LocalVariableConversion conversion) { + return new JumpToInlinedFinally(this, conversion); + } + + @Override + String getStatementName() { + return ":jumpToInlinedFinally"; + } + + @Override + public Block getTarget(final LexicalContext lc) { + return lc.getInlinedFinally(getLabelName()); + } + + @Override + public TryNode getPopScopeLimit(final LexicalContext lc) { + // Returns the try node to which this jump's target belongs. This will make scope popping also pop the scope + // for the body of the try block, if it needs scope. + return lc.getTryNodeForInlinedFinally(getLabelName()); + } + + @Override + Label getTargetLabel(final BreakableNode target) { + assert target != null; + // We're jumping to the entry of the inlined finally block + return ((Block)target).getEntryLabel(); + } +} diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java index 487d6aeb7af..8fbb2bca538 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java @@ -190,7 +190,7 @@ public class LexicalContext { * @return the node that was popped */ @SuppressWarnings("unchecked") - public T pop(final T node) { + public T pop(final T node) { --sp; final LexicalContextNode popped = stack[sp]; stack[sp] = null; @@ -469,7 +469,7 @@ public class LexicalContext { * scopes that need to be explicitly popped in order to perform a break or continue jump within the current bytecode * method. For this reason, the method returns 0 if it encounters a {@code SplitNode} between the current location * and the break/continue target. - * @param until node to stop counting at. Must be within the current function + * @param until node to stop counting at. Must be within the current function * @return number of with scopes encountered in the context */ public int getScopeNestingLevelTo(final LexicalContextNode until) { @@ -564,12 +564,42 @@ public class LexicalContext { return getContinueTo(); } + /** + * Find the inlined finally block node corresponding to this label. + * @param labelName label name to search for. Must not be null. + * @return closest inlined finally block with the given label + */ + public Block getInlinedFinally(final String labelName) { + for (final NodeIterator iter = new NodeIterator<>(TryNode.class); iter.hasNext(); ) { + final Block inlinedFinally = iter.next().getInlinedFinally(labelName); + if (inlinedFinally != null) { + return inlinedFinally; + } + } + return null; + } + + /** + * Find the try node for an inlined finally block corresponding to this label. + * @param labelName label name to search for. Must not be null. + * @return the try node to which the labelled inlined finally block belongs. + */ + public TryNode getTryNodeForInlinedFinally(final String labelName) { + for (final NodeIterator iter = new NodeIterator<>(TryNode.class); iter.hasNext(); ) { + final TryNode tryNode = iter.next(); + if (tryNode.getInlinedFinally(labelName) != null) { + return tryNode; + } + } + return null; + } + /** * Check the lexical context for a given label node by name * @param name name of the label * @return LabelNode if found, null otherwise */ - public LabelNode findLabel(final String name) { + private LabelNode findLabel(final String name) { for (final Iterator iter = new NodeIterator<>(LabelNode.class, getCurrentFunction()); iter.hasNext(); ) { final LabelNode next = iter.next(); if (next.getLabelName().equals(name)) { @@ -592,6 +622,12 @@ public class LexicalContext { return true; } else if (next == target) { return false; + } else if (next instanceof TryNode) { + for(final Block inlinedFinally: ((TryNode)next).getInlinedFinallies()) { + if (TryNode.getLabelledInlinedFinallyBlock(inlinedFinally) == target) { + return false; + } + } } } throw new AssertionError(target + " was expected in lexical context " + LexicalContext.this + " but wasn't"); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContextNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContextNode.java index b53d9f6b1a2..5054b014f0e 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContextNode.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContextNode.java @@ -54,8 +54,8 @@ public interface LexicalContextNode { static Node accept(final LexicalContextNode node, final NodeVisitor visitor) { final LexicalContext lc = visitor.getLexicalContext(); lc.push(node); - final LexicalContextNode newNode = (LexicalContextNode)node.accept(lc, visitor); - return (Node)lc.pop(newNode); + final Node newNode = node.accept(lc, visitor); + return lc.pop(newNode); } } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/OptimisticLexicalContext.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/OptimisticLexicalContext.java index 9d97a43810d..18f68fe676c 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/OptimisticLexicalContext.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/OptimisticLexicalContext.java @@ -115,7 +115,7 @@ public class OptimisticLexicalContext extends LexicalContext { } @Override - public T pop(final T node) { + public T pop(final T node) { final T popped = super.pop(node); if (isEnabled) { if(node instanceof FunctionNode) { diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java index 605e0a9ec27..9e68ee87732 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java @@ -27,7 +27,9 @@ package jdk.nashorn.internal.ir; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.visitor.NodeVisitor; @@ -35,7 +37,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor; * IR representation of a TRY statement. */ @Immutable -public final class TryNode extends Statement implements JoinPredecessor { +public final class TryNode extends LexicalContextStatement implements JoinPredecessor { private static final long serialVersionUID = 1L; /** Try statements. */ @@ -47,12 +49,24 @@ public final class TryNode extends Statement implements JoinPredecessor { /** Finally clause. */ private final Block finallyBody; + /** + * List of inlined finally blocks. The structure of every inlined finally is: + * Block(LabelNode(label, Block(finally-statements, (JumpStatement|ReturnNode)?))). + * That is, the block has a single LabelNode statement with the label and a block containing the + * statements of the inlined finally block with the jump or return statement appended (if the finally + * block was not terminal; the original jump/return is simply ignored if the finally block itself + * terminates). The reason for this somewhat strange arrangement is that we didn't want to create a + * separate class for the (label, BlockStatement pair) but rather reused the already available LabelNode. + * However, if we simply used List without wrapping the label nodes in an additional Block, + * that would've thrown off visitors relying on BlockLexicalContext -- same reason why we never use + * Statement as the type of bodies of e.g. IfNode, WhileNode etc. but rather blockify them even when they're + * single statements. + */ + private final List inlinedFinallies; + /** Exception symbol. */ private Symbol exception; - /** Catchall exception for finally expansion, where applicable */ - private Symbol finallyCatchAll; - private final LocalVariableConversion conversion; /** @@ -71,21 +85,23 @@ public final class TryNode extends Statement implements JoinPredecessor { this.catchBlocks = catchBlocks; this.finallyBody = finallyBody; this.conversion = null; + this.inlinedFinallies = Collections.emptyList(); } - private TryNode(final TryNode tryNode, final Block body, final List catchBlocks, final Block finallyBody, final LocalVariableConversion conversion) { + private TryNode(final TryNode tryNode, final Block body, final List catchBlocks, final Block finallyBody, final LocalVariableConversion conversion, final List inlinedFinallies) { super(tryNode); this.body = body; this.catchBlocks = catchBlocks; this.finallyBody = finallyBody; this.conversion = conversion; + this.inlinedFinallies = inlinedFinallies; this.exception = tryNode.exception; } @Override public Node ensureUniqueLabels(final LexicalContext lc) { //try nodes are never in lex context - return new TryNode(this, body, catchBlocks, finallyBody, conversion); + return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies); } @Override @@ -106,16 +122,16 @@ public final class TryNode extends Statement implements JoinPredecessor { * @param visitor IR navigating visitor. */ @Override - public Node accept(final NodeVisitor visitor) { + public Node accept(final LexicalContext lc, NodeVisitor visitor) { if (visitor.enterTryNode(this)) { // Need to do finallybody first for termination analysis. TODO still necessary? final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor); final Block newBody = (Block)body.accept(visitor); return visitor.leaveTryNode( - setBody(newBody). - setFinallyBody(newFinallyBody). - setCatchBlocks(Node.accept(visitor, catchBlocks)). - setFinallyCatchAll(finallyCatchAll)); + setBody(lc, newBody). + setFinallyBody(lc, newFinallyBody). + setCatchBlocks(lc, Node.accept(visitor, catchBlocks)). + setInlinedFinallies(lc, Node.accept(visitor, inlinedFinallies))); } return this; @@ -136,14 +152,15 @@ public final class TryNode extends Statement implements JoinPredecessor { /** * Reset the body of this try block + * @param lc current lexical context * @param body new body * @return new TryNode or same if unchanged */ - public TryNode setBody(final Block body) { + public TryNode setBody(final LexicalContext lc, final Block body) { if (this.body == body) { return this; } - return new TryNode(this, body, catchBlocks, finallyBody, conversion); + return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies)); } /** @@ -172,14 +189,15 @@ public final class TryNode extends Statement implements JoinPredecessor { /** * Set the catch blocks of this try + * @param lc current lexical context * @param catchBlocks list of catch blocks * @return new TryNode or same if unchanged */ - public TryNode setCatchBlocks(final List catchBlocks) { + public TryNode setCatchBlocks(final LexicalContext lc, final List catchBlocks) { if (this.catchBlocks == catchBlocks) { return this; } - return new TryNode(this, body, catchBlocks, finallyBody, conversion); + return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies)); } /** @@ -199,27 +217,6 @@ public final class TryNode extends Statement implements JoinPredecessor { return this; } - /** - * Get the catch all symbol for this try block - * @return catch all symbol - */ - public Symbol getFinallyCatchAll() { - return this.finallyCatchAll; - } - - /** - * If a finally block exists, the synthetic catchall needs another symbol to - * store its throwable - * @param finallyCatchAll a symbol for the finally catch all exception - * @return new TryNode or same if unchanged - * - * TODO can this still be stateful? - */ - public TryNode setFinallyCatchAll(final Symbol finallyCatchAll) { - this.finallyCatchAll = finallyCatchAll; - return this; - } - /** * Get the body of the finally clause for this try * @return finally body, or null if no finally @@ -228,16 +225,88 @@ public final class TryNode extends Statement implements JoinPredecessor { return finallyBody; } + /** + * Get the inlined finally block with the given label name. This returns the actual finally block in the + * {@link LabelNode}, not the outer wrapper block for the {@link LabelNode}. + * @param labelName the name of the inlined finally's label + * @return the requested finally block, or null if no finally block's label matches the name. + */ + public Block getInlinedFinally(final String labelName) { + for(final Block inlinedFinally: inlinedFinallies) { + final LabelNode labelNode = getInlinedFinallyLabelNode(inlinedFinally); + if (labelNode.getLabelName().equals(labelName)) { + return labelNode.getBody(); + } + } + return null; + } + + private static LabelNode getInlinedFinallyLabelNode(final Block inlinedFinally) { + return (LabelNode)inlinedFinally.getStatements().get(0); + } + + /** + * Given an outer wrapper block for the {@link LabelNode} as returned by {@link #getInlinedFinallies()}, + * returns its actual inlined finally block. + * @param inlinedFinally the outer block for inlined finally, as returned as an element of + * {@link #getInlinedFinallies()}. + * @return the block contained in the {@link LabelNode} contained in the passed block. + */ + public static Block getLabelledInlinedFinallyBlock(final Block inlinedFinally) { + return getInlinedFinallyLabelNode(inlinedFinally).getBody(); + } + + /** + * Returns a list of inlined finally blocks. Note that this returns a list of {@link Block}s such that each one of + * them has a single {@link LabelNode}, which in turn contains the label name for the finally block and the + * actual finally block. To safely extract the actual finally block, use + * {@link #getLabelledInlinedFinallyBlock(Block)}. + * @return a list of inlined finally blocks. + */ + public List getInlinedFinallies() { + return Collections.unmodifiableList(inlinedFinallies); + } + /** * Set the finally body of this try + * @param lc current lexical context * @param finallyBody new finally body * @return new TryNode or same if unchanged */ - public TryNode setFinallyBody(final Block finallyBody) { + public TryNode setFinallyBody(final LexicalContext lc, final Block finallyBody) { if (this.finallyBody == finallyBody) { return this; } - return new TryNode(this, body, catchBlocks, finallyBody, conversion); + return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies)); + } + + /** + * Set the inlined finally blocks of this try. Each element should be a block with a single statement that is a + * {@link LabelNode} with a unique label, and the block within the label node should contain the actual inlined + * finally block. + * @param lc current lexical context + * @param inlinedFinallies list of inlined finally blocks + * @return new TryNode or same if unchanged + */ + public TryNode setInlinedFinallies(final LexicalContext lc, final List inlinedFinallies) { + if (this.inlinedFinallies == inlinedFinallies) { + return this; + } + assert checkInlinedFinallies(inlinedFinallies); + return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies)); + } + + private static boolean checkInlinedFinallies(final List inlinedFinallies) { + if (!inlinedFinallies.isEmpty()) { + final Set labels = new HashSet<>(); + for (final Block inlinedFinally : inlinedFinallies) { + final List stmts = inlinedFinally.getStatements(); + assert stmts.size() == 1; + final LabelNode ln = getInlinedFinallyLabelNode(inlinedFinally); + assert labels.add(ln.getLabelName()); // unique label + } + } + return true; } @Override @@ -245,7 +314,7 @@ public final class TryNode extends Statement implements JoinPredecessor { if(this.conversion == conversion) { return this; } - return new TryNode(this, body, catchBlocks, finallyBody, conversion); + return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies); } @Override diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java index 52e9b66311e..47fc0449191 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java @@ -391,6 +391,9 @@ public final class PrintVisitor extends NodeVisitor { finallyBody.accept(this); } + for (final Block inlinedFinally : tryNode.getInlinedFinallies()) { + inlinedFinally.accept(this); + } return false; } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java index f9fd3862c6c..28022b1baaa 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java @@ -43,6 +43,7 @@ import jdk.nashorn.internal.ir.IdentNode; import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IndexNode; import jdk.nashorn.internal.ir.JoinPredecessorExpression; +import jdk.nashorn.internal.ir.JumpToInlinedFinally; import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; @@ -472,6 +473,26 @@ public abstract class NodeVisitor { return leaveDefault(indexNode); } + /** + * Callback for entering a JumpToInlinedFinally + * + * @param jumpToInlinedFinally the node + * @return true if traversal should continue and node children be traversed, false otherwise + */ + public boolean enterJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) { + return enterDefault(jumpToInlinedFinally); + } + + /** + * Callback for leaving a JumpToInlinedFinally + * + * @param jumpToInlinedFinally the node + * @return processed node, which will replace the original one, or the original node + */ + public Node leaveJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) { + return leaveDefault(jumpToInlinedFinally); + } + /** * Callback for entering a LabelNode * diff --git a/nashorn/test/script/basic/JDK-8067139.js b/nashorn/test/script/basic/JDK-8067139.js new file mode 100644 index 00000000000..004efe155b7 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8067139.js @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014 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. + */ + +/** + * JDK-8067139: Finally blocks inlined incorrectly + * + * @test + * @run + */ + +// Test case for JDK-8067139 +// as well as for JDK-8030198 which is a duplicate. +(function(){ + var catchCount = 0; + try { + (function (){ + try { + return; + } catch(x) { + ++catchCount; + } finally { + throw 0; + } + })(); + Assert.fail(); // must throw + } catch(e) { + Assert.assertEquals(e, 0); // threw 0 + Assert.assertEquals(catchCount, 0); // inner catch never executed + } +})(); + +// Test case for JDK-8048862 which is a duplicate of this bug +var ret = (function(o) { + try{ + with(o) { + return x; + } + } finally { + try { + return x; + } catch(e) { + Assert.assertTrue(e instanceof ReferenceError); + return 2; + } + } +})({x: 1}); +Assert.assertEquals(ret, 2); // executed the catch block + +// Test cases for JDK-8066231 that is a duplicate of this bug +// Case 1 +(function (){ try { Object; } catch(x if x >>>=0) { throw x2; } finally { } })(); +// Case 2 +try { + (function (){ try { return; } catch(x) { return x ^= 0; } finally { throw 0; } })(); + Assert.fail(); +} catch(e) { + Assert.assertEquals(e, 0); // threw 0 +} +// Case 3 +try { + (function (){ try { return; } catch(x) { return x ^= Object; } finally { throw Object; } })(); + Assert.fail(); +} catch(e) { + Assert.assertEquals(e, Object); // threw Object +} +// Case from comment +try { + (function () { try { Object } catch(x) { (x=y); return; } finally { throw Object; } })(); + Assert.fail(); +} catch(e) { + Assert.assertEquals(e, Object); // threw Object +} From f1948ccbb5a98fb3b1a41c7c03e760bb44f6770a Mon Sep 17 00:00:00 2001 From: Frank Yuan Date: Wed, 28 Jan 2015 15:07:12 -0800 Subject: [PATCH 52/72] 8052401: JAXP function gap tests conversion Reviewed-by: lancea, joehw --- .../functional/test/gaptest/Bug4511326.java | 63 +++++ .../functional/test/gaptest/Bug4512806.java | 88 +++++++ .../functional/test/gaptest/Bug4515047.java | 61 +++++ .../functional/test/gaptest/Bug4515660.java | 123 +++++++++ .../functional/test/gaptest/Bug4693341.java | 79 ++++++ .../functional/test/gaptest/Bug4848653.java | 80 ++++++ .../functional/test/gaptest/Bug4858685.java | 246 ++++++++++++++++++ .../test/gaptest/xmlfiles/Bug4693341.dtd | 39 +++ .../test/gaptest/xmlfiles/Bug4693341.xml | 20 ++ .../test/gaptest/xmlfiles/Bug4848653.xml | 1 + .../test/gaptest/xmlfiles/certificate.xml | 27 ++ .../test/gaptest/xmlfiles/out/Bug4693341.dtd | 39 +++ .../test/gaptest/xmlfiles/out/Bug4693341.xml | 20 ++ .../test/gaptest/xmlfiles/out/Bug4858685.txt | 30 +++ .../jaxp/libs/test/gaptest/GapTestConst.java | 41 +++ 15 files changed, 957 insertions(+) create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4511326.java create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4512806.java create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515047.java create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515660.java create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4693341.java create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4848653.java create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4858685.java create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.dtd create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.xml create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4848653.xml create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/certificate.xml create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.dtd create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.xml create mode 100644 jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4858685.txt create mode 100644 jaxp/test/javax/xml/jaxp/libs/test/gaptest/GapTestConst.java diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4511326.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4511326.java new file mode 100644 index 00000000000..fec94a13174 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4511326.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003, 2015, 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 test.gaptest; + +import java.io.StringReader; + +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamSource; + +import jaxp.library.JAXPBaseTest; + +import org.testng.annotations.Test; + +/* + * @bug 4511326 + * @summary In forwards-compatible mode the attribute isn't ignored + */ + +public class Bug4511326 extends JAXPBaseTest { + + private static final String XSL = "" + + "" + + "

    " + + "

    " + + "" + + ""; + + + @Test + public void ignoreAttTest() throws TransformerConfigurationException { + /* Create a TransformFactory instance */ + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + + /* Create and init a StreamSource instance */ + StreamSource source = new StreamSource(new StringReader(XSL)); + + transformerFactory.newTransformer(source); + } + +} diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4512806.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4512806.java new file mode 100644 index 00000000000..631b0919ec7 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4512806.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2003, 2015, 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 test.gaptest; + +import static javax.xml.transform.OutputKeys.ENCODING; +import static javax.xml.transform.OutputKeys.INDENT; +import static org.testng.Assert.assertEquals; + +import java.io.StringReader; + +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamSource; + +import jaxp.library.JAXPBaseTest; + +import org.testng.annotations.Test; + +/* + * @bug 4512806 + * @summary test transformer.setOutputProperties(null) + */ +public class Bug4512806 extends JAXPBaseTest { + + @Test + public void testProperty() throws TransformerConfigurationException { + /* Create a transform factory instance */ + TransformerFactory tfactory = TransformerFactory.newInstance(); + + /* Create a StreamSource instance */ + StreamSource streamSource = new StreamSource(new StringReader(xslData)); + + transformer = tfactory.newTransformer(streamSource); + transformer.setOutputProperty(INDENT, "no"); + transformer.setOutputProperty(ENCODING, "UTF-16"); + + assertEquals(printPropertyValue(INDENT), "indent=no"); + assertEquals(printPropertyValue(ENCODING), "encoding=UTF-16"); + + transformer.setOutputProperties(null); + + assertEquals(printPropertyValue(INDENT), "indent=yes"); + assertEquals(printPropertyValue(ENCODING), "encoding=UTF-8"); + + } + + private String printPropertyValue(String name) { + return name + "=" + transformer.getOutputProperty(name); + } + + private Transformer transformer; + + private static final String xslData = "" + + "\n" + + " \n" + + " \n" + + " Hello World! \n" + + " \n" + + ""; + + +} diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515047.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515047.java new file mode 100644 index 00000000000..0b822c810ef --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515047.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2003, 2015, 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 test.gaptest; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import jaxp.library.JAXPBaseTest; + +import org.testng.annotations.Test; + +/* + * @bug 4515047 + * @summary test transform an empty dom source + */ + +public class Bug4515047 extends JAXPBaseTest { + + @Test + public void testCreateTxDoc() throws TransformerException, ParserConfigurationException { + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + + StreamResult result = new StreamResult(System.out); + DOMSource source = new DOMSource(); + + /* This should not throw an Illegal Argument Exception */ + //Test empty DOMSource + transformer.transform(source, result); + + //Test DOMSource having only an empty node + source.setNode(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()); + transformer.transform(source, result); + } + +} diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515660.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515660.java new file mode 100644 index 00000000000..6f2c3140555 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515660.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2003, 2015, 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 test.gaptest; + +import static org.testng.Assert.assertTrue; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.stream.StreamResult; + +import jaxp.library.JAXPBaseTest; + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.XMLFilterImpl; + +/* + * @bug 4515660 + * @summary verify property org.xml.sax.driver is used by SAXTransformerFactory + */ +@Test(singleThreaded = true) +public class Bug4515660 extends JAXPBaseTest { + + @BeforeClass + public void setSaxDrier() { + setSystemProperty("org.xml.sax.driver", ReaderStub.class.getName()); + } + + @AfterClass + public void clearSaxDrier() { + setSystemProperty("org.xml.sax.driver", null); + } + + @Test + public void testTransformer() throws TransformerException { + String xml = ""; + ReaderStub.used = false; + + TransformerFactory transFactory = TransformerFactory.newInstance(); + Transformer transformer = transFactory.newTransformer(); + InputSource in = new InputSource(new StringReader(xml)); + SAXSource source = new SAXSource(in); + StreamResult result = new StreamResult(new StringWriter()); + + transformer.transform(source, result); + + assertTrue(ReaderStub.used); + + } + + @Test + public void testSAXTransformerFactory() throws TransformerConfigurationException { + final String xsl = "\n" + "\n" + + " Hello World!\n" + "\n"; + + ReaderStub.used = false; + + TransformerFactory transFactory = TransformerFactory.newInstance(); + assertTrue(transFactory.getFeature(SAXTransformerFactory.FEATURE)); + + InputSource in = new InputSource(new StringReader(xsl)); + SAXSource source = new SAXSource(in); + + transFactory.newTransformer(source); + assertTrue(ReaderStub.used); + + } + + public static class ReaderStub extends XMLFilterImpl { + static boolean used = false; + + public ReaderStub() throws ParserConfigurationException, SAXException { + super(); + super.setParent(SAXParserFactory.newInstance().newSAXParser().getXMLReader()); + used = true; + } + + public void parse(InputSource input) throws SAXException, IOException { + used = true; + super.parse(input); + } + + public void parse(String systemId) throws SAXException, IOException { + used = true; + super.parse(systemId); + } + } + +} diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4693341.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4693341.java new file mode 100644 index 00000000000..d7d586b584c --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4693341.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2003, 2015, 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 test.gaptest; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static jaxp.library.JAXPTestUtilities.USER_DIR; +import static jaxp.library.JAXPTestUtilities.compareDocumentWithGold; +import static org.testng.Assert.assertTrue; +import static test.gaptest.GapTestConst.GOLDEN_DIR; +import static test.gaptest.GapTestConst.XML_DIR; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import jaxp.library.JAXPFileBaseTest; + +import org.testng.annotations.Test; +import org.xml.sax.SAXException; + +/* + * @bug 4693341 + * @summary test transforming to stream with external dtd + */ + +public class Bug4693341 extends JAXPFileBaseTest { + + @Test + public void test() throws TransformerException, ParserConfigurationException, SAXException, IOException { + + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + + String out = USER_DIR + File.separator + "Bug4693341.out"; + StreamResult result = new StreamResult(new File(out)); + + String in = XML_DIR + "Bug4693341.xml"; + String golden = GOLDEN_DIR + "Bug4693341.xml"; + File file = new File(in); + StreamSource source = new StreamSource(file); + System.out.println(source.getSystemId()); + + Files.copy(Paths.get(XML_DIR + "Bug4693341.dtd"), + Paths.get(USER_DIR + File.separator + "Bug4693341.dtd"), REPLACE_EXISTING); + + transformer.transform(source, result); + + assertTrue(compareDocumentWithGold(golden, out)); + } + +} diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4848653.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4848653.java new file mode 100644 index 00000000000..f4de7753162 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4848653.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2003, 2015, 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 test.gaptest; + +import static jaxp.library.JAXPTestUtilities.filenameToURL; +import static test.gaptest.GapTestConst.XML_DIR; + +import java.io.IOException; + +import javax.xml.XMLConstants; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import jaxp.library.JAXPFileBaseTest; + +import org.testng.annotations.Test; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; + +/* + * @bug 4848653 + * @summary Verify JAXP schemaLanguage property is ignored if setValidating(false) + */ + +public class Bug4848653 extends JAXPFileBaseTest { + + @Test + public void test() throws IOException, SAXException, ParserConfigurationException { + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setValidating(false); + SAXParser parser = factory.newSAXParser(); + parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", XMLConstants.W3C_XML_SCHEMA_NS_URI); + + String filename = XML_DIR + "Bug4848653.xml"; + InputSource is = new InputSource(filenameToURL(filename)); + XMLReader xmlReader = parser.getXMLReader(); + xmlReader.setErrorHandler(new MyErrorHandler()); + xmlReader.parse(is); + } + + class MyErrorHandler implements ErrorHandler { + public void error(SAXParseException exception) throws SAXParseException { + throw exception; + } + + public void warning(SAXParseException exception) throws SAXParseException { + throw exception; + } + + public void fatalError(SAXParseException exception) throws SAXParseException { + throw exception; + } + + } + +} diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4858685.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4858685.java new file mode 100644 index 00000000000..5dd54017c62 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4858685.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2003, 2015, 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 test.gaptest; + +import static jaxp.library.JAXPTestUtilities.filenameToURL; +import static org.testng.Assert.assertEquals; +import static test.gaptest.GapTestConst.GOLDEN_DIR; +import static test.gaptest.GapTestConst.XML_DIR; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.stream.StreamSource; + +import jaxp.library.JAXPFileBaseTest; + +import org.testng.annotations.Test; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/* + * @bug 4858685 4894410 + * @summary test transforming text node + */ + +public class Bug4858685 extends JAXPFileBaseTest { + @Test + public void test() throws TransformerException, IOException { + String uri = XML_DIR + "certificate.xml"; + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + + Transformer transformer = transformerFactory.newTransformer(); + + // use URI as a StreamSource + StreamSource streamSource = new StreamSource(filenameToURL(uri)); + + DOMResult domResult = new DOMResult(); + + // StreamSource -> DOMResult + transformer.transform(streamSource, domResult); + + // dump DOM in a human readable form + String gotString = DOMDump.dumpDom(domResult.getNode()); + + String goldenString = new String(Files.readAllBytes(Paths.get(GOLDEN_DIR + "Bug4858685.txt"))); + + assertEquals(gotString, goldenString); + + } + + /** + * DOMDump: dump a DOM to a String in human readable form. method dumpDOM() + * is static for easy calling: + */ + private static class DOMDump { + + /** + * the maximum level to indent with blanks + */ + private static final int BLANKS_LEN = 64; + + /** + * each level of the tree will be indented with blanks for readability + */ + private static final String BLANKS = " "; + + /** + * dumpDOM will dump the DOM into a String for human readability + * + * @param domNode + * the DOM Node to dump + * @return human readabile DOM as a String + */ + public static String dumpDom(Node domNode) { + return dumpInternal(domNode, 0); + } + + /** + * dumpInternal is used internaly to recursively dump DOM Nodes + * + * @param domNode + * to dump + * @param indent + * level + * @return domNode as human readable String + */ + private static String dumpInternal(Node domNode, int indent) { + + String result = ""; + + // indent for readability + result += indentBlanks(indent); + indent += 2; + + // protect against null + if (domNode == null) { + result = result + "[null]" + "\n"; + return result; + } + + // what to output depends on NodeType + short type = domNode.getNodeType(); + switch (type) { + case Node.ATTRIBUTE_NODE: { + result += "[attribute] " + domNode.getNodeName() + "=\"" + domNode.getNodeValue() + "\""; + break; + } + case Node.CDATA_SECTION_NODE: { + result += "[cdata] " + domNode.getNodeValue(); + break; + } + case Node.COMMENT_NODE: { + result += "[comment] " + domNode.getNodeValue(); + break; + } + case Node.DOCUMENT_FRAGMENT_NODE: { + result += "[document fragment]"; + break; + } + case Node.DOCUMENT_NODE: { + result += "[document]"; + break; + } + case Node.DOCUMENT_TYPE_NODE: { + result += "[document type] " + domNode.getNodeName(); + break; + } + case Node.ELEMENT_NODE: { + result += "[element] " + domNode.getNodeName(); + // output all attributes for Element + if (domNode.hasAttributes()) { + NamedNodeMap attributes = domNode.getAttributes(); + for (int onAttribute = 0; onAttribute < attributes.getLength(); onAttribute++) { + + // seprate each attribute with a space + result += " "; + + Node attribute = attributes.item(onAttribute); + String namespaceURI = attribute.getNamespaceURI(); + String prefix = attribute.getPrefix(); + String localName = attribute.getLocalName(); + String name = attribute.getNodeName(); + String value = attribute.getNodeValue(); + + // using Namespaces? + if (namespaceURI != null) { + result += "{" + namespaceURI + "}"; + } + if (prefix != null) { + result += prefix + ":"; + } + + // name="value" + result += attribute.getNodeName() + "=\"" + attribute.getNodeValue() + "\""; + } + } + + break; + } + case Node.ENTITY_NODE: { + result += "[entity] " + domNode.getNodeName(); + break; + } + case Node.ENTITY_REFERENCE_NODE: { + result += "[entity reference] " + domNode.getNodeName(); + break; + } + case Node.NOTATION_NODE: { + result += "[notation] " + domNode.getNodeName(); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE: { + result += "[pi] target=\"" + domNode.getNodeName() + "\" content=\"" + domNode.getNodeValue() + "\""; + break; + } + case Node.TEXT_NODE: { + result += "[text] " + domNode.getNodeValue(); + break; + } + default: { + result += "[unknown]"; + break; + } + } + + // humans read in lines + result += "\n"; + + // process children + NodeList children = domNode.getChildNodes(); + for (int onChild = 0; onChild < children.getLength(); onChild++) { + Node child = children.item(onChild); + result += dumpInternal(child, indent); + } + + // return human readable DOM as String + return result; + } + + /** + * indentBlanks will return a String of indent blanks + * + * @param indent + * level + * @return String of blanks + */ + private static String indentBlanks(int indent) { + if (indent == 0) { + return ""; + } + + if (indent > BLANKS_LEN) { + return BLANKS; + } + + return BLANKS.substring(0, indent + 1); + } + + } +} diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.dtd b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.dtd new file mode 100644 index 00000000000..23e6411665d --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.dtd @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.xml b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.xml new file mode 100644 index 00000000000..96fad2304ec --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.xml @@ -0,0 +1,20 @@ + + + +10016 +Wed May 29 12:45:00 PDT 2002 + +ABC +XYZ +1234 Anywhere Street +Palo Alto +California +USA +94303 +NULL +NULL + + + + + diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4848653.xml b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4848653.xml new file mode 100644 index 00000000000..d80a5e273cc --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4848653.xml @@ -0,0 +1 @@ + diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/certificate.xml b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/certificate.xml new file mode 100644 index 00000000000..e56e16a0abb --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/certificate.xml @@ -0,0 +1,27 @@ + + + + + +MIIDVjCCAxICBD6kKrMwCwYHKoZIzjgEAwUAMIGPMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex +FDASBgNVBAcTC1NhbnRhIENsYXJhMR8wHQYDVQQKExZTdW4gTWljcm9zeXN0ZW1zLCBJbmMuMR4w +HAYDVQQLExVKYXZhIGFuZCBYTUwgU29mdHdhcmUxHDAaBgNVBAMTE0pXUy1TZWN1cml0eSBDbGll +bnQwHhcNMDMwNDIxMTczMDI3WhcNMDMwNzIwMTczMDI3WjCBjzELMAkGA1UEBhMCVVMxCzAJBgNV +BAgTAkNBMRQwEgYDVQQHEwtTYW50YSBDbGFyYTEfMB0GA1UEChMWU3VuIE1pY3Jvc3lzdGVtcywg +SW5jLjEeMBwGA1UECxMVSmF2YSBhbmQgWE1MIFNvZnR3YXJlMRwwGgYDVQQDExNKV1MtU2VjdXJp +dHkgQ2xpZW50MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E +AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up +1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUj +C8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZ +T+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7 +zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAV3R+bUfh+u0yaPBV75umKvFB +ucv37ETDak889b7k72kZdGoHz3oDmp69tiNDg5r7IvKtjHGbZ6C3Nv0ycNR7Sed1QPOF4nn/tgUl +j+BvtVW3iiIRgBJ82KP+28QtwPkkxSp7n5HG0v7bE29E/juLduuhKBQTaaCvajuCFxiBrmAwCwYH +KoZIzjgEAwUAAzEAMC4CFQCCuDNmMKjgY6MV1SmAcCdnhuT6VwIVAJBOiPDnDWp2WlKAERF6nOAf +vKz9 + + + diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.dtd b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.dtd new file mode 100644 index 00000000000..23e6411665d --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.dtd @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.xml b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.xml new file mode 100644 index 00000000000..96fad2304ec --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.xml @@ -0,0 +1,20 @@ + + + +10016 +Wed May 29 12:45:00 PDT 2002 + +ABC +XYZ +1234 Anywhere Street +Palo Alto +California +USA +94303 +NULL +NULL + + + + + diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4858685.txt b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4858685.txt new file mode 100644 index 00000000000..91ee2de9052 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4858685.txt @@ -0,0 +1,30 @@ +[document] + [element] env:Envelope {http://www.w3.org/2000/xmlns/}xmlns:xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/" {http://www.w3.org/2000/xmlns/}xmlns:xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" {http://www.w3.org/2000/xmlns/}xmlns:xmlns:ns0="http://headertest.org/" {http://www.w3.org/2000/xmlns/}xmlns:xmlns:xsd="http://www.w3.org/2001/XMLSchema" {http://www.w3.org/2000/xmlns/}xmlns:xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + [text] + + [element] env:Body + [text] + + [element] ds:X509Certificate xmlns="" {http://www.w3.org/2000/xmlns/}xmlns:xmlns:ds="http://www.w3.org/2000/09/xmldsig#" + [text] +MIIDVjCCAxICBD6kKrMwCwYHKoZIzjgEAwUAMIGPMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex +FDASBgNVBAcTC1NhbnRhIENsYXJhMR8wHQYDVQQKExZTdW4gTWljcm9zeXN0ZW1zLCBJbmMuMR4w +HAYDVQQLExVKYXZhIGFuZCBYTUwgU29mdHdhcmUxHDAaBgNVBAMTE0pXUy1TZWN1cml0eSBDbGll +bnQwHhcNMDMwNDIxMTczMDI3WhcNMDMwNzIwMTczMDI3WjCBjzELMAkGA1UEBhMCVVMxCzAJBgNV +BAgTAkNBMRQwEgYDVQQHEwtTYW50YSBDbGFyYTEfMB0GA1UEChMWU3VuIE1pY3Jvc3lzdGVtcywg +SW5jLjEeMBwGA1UECxMVSmF2YSBhbmQgWE1MIFNvZnR3YXJlMRwwGgYDVQQDExNKV1MtU2VjdXJp +dHkgQ2xpZW50MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E +AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up +1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUj +C8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZ +T+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7 +zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAV3R+bUfh+u0yaPBV75umKvFB +ucv37ETDak889b7k72kZdGoHz3oDmp69tiNDg5r7IvKtjHGbZ6C3Nv0ycNR7Sed1QPOF4nn/tgUl +j+BvtVW3iiIRgBJ82KP+28QtwPkkxSp7n5HG0v7bE29E/juLduuhKBQTaaCvajuCFxiBrmAwCwYH +KoZIzjgEAwUAAzEAMC4CFQCCuDNmMKjgY6MV1SmAcCdnhuT6VwIVAJBOiPDnDWp2WlKAERF6nOAf +vKz9 + + [text] + + [text] + diff --git a/jaxp/test/javax/xml/jaxp/libs/test/gaptest/GapTestConst.java b/jaxp/test/javax/xml/jaxp/libs/test/gaptest/GapTestConst.java new file mode 100644 index 00000000000..237d0ac6ed2 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/test/gaptest/GapTestConst.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, 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 test.gaptest; + +import static jaxp.library.JAXPTestUtilities.FILE_SEP; +import static jaxp.library.JAXPTestUtilities.getPathByClassName; + +/** + * This class defines the path constant + */ +public class GapTestConst { + /** + * XML source file directory. + */ + public static final String XML_DIR = getPathByClassName(GapTestConst.class, "xmlfiles"); + + /** + * Golden validation files directory. + */ + public static final String GOLDEN_DIR = getPathByClassName(GapTestConst.class, "xmlfiles" + FILE_SEP + "out"); +} From 99089c5210ff28759ac00b6432900838ed43e456 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 28 Jan 2015 16:45:32 -0800 Subject: [PATCH 53/72] Added tag jdk9-b48 for changeset f4f2bb7513e4 --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index e95f2721df1..26c2321b403 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -290,3 +290,4 @@ f7c11da0b0481d49cc7a65a453336c108191e821 jdk9-b42 3dd628fde2086218d548841022ee8436b6b88185 jdk9-b45 12f1e276447bcc81516e85367d53e4f08897049d jdk9-b46 b6cca3e6175a69f39e5799b7349ddb0176630291 jdk9-b47 +0064e246d83f6f9fc245c19b6d05041ecaf4b6d4 jdk9-b48 From 93198a3c0c75a12bab6f530b3da32df2cfd083de Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 28 Jan 2015 16:45:33 -0800 Subject: [PATCH 54/72] Added tag jdk9-b48 for changeset bb8de1967725 --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index a6362dd4bef..5fa0c422fef 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -290,3 +290,4 @@ e27c725d6c9d155667b35255f442d4ceb8c3c084 jdk9-b40 9e3f2bed80c0e5a84a256ce41f1d10c5ade48466 jdk9-b45 326f2068b4a4c05e2fa27d6acf93eba7b54b090d jdk9-b46 ee8447ca632e1d39180b4767c749db101bff7314 jdk9-b47 +a13c49c5f2899b702652a460ed7aa73123e671e6 jdk9-b48 From a29d6a494d78a15170122a3637b077cf82bc51bb Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 28 Jan 2015 16:45:35 -0800 Subject: [PATCH 55/72] Added tag jdk9-b48 for changeset adf10d73e78b --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 5d7b668b46c..a0e96eab962 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -450,3 +450,4 @@ c363a8b87e477ee45d6d3cb2a36cb365141bc596 jdk9-b38 5dc8184af1e2bb30b0103113d1f1a58a21a80c37 jdk9-b45 a184ee1d717297bd35b7c3e35393e137921a3ed2 jdk9-b46 3b241fb72b8925b75941d612db762a6d5da66d02 jdk9-b47 +cc775a4a24c7f5d9e624b4205e9fbd48a17331f6 jdk9-b48 From 971b575c25769c601ba5c7547d036e358e01cba4 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 28 Jan 2015 16:45:37 -0800 Subject: [PATCH 56/72] Added tag jdk9-b48 for changeset 5da8936a1a2c --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index c0eb212b48c..664424cb343 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -290,3 +290,4 @@ a12d347f84176200593999f4da91ae2bb86865b2 jdk9-b39 0dab3e848229127c7aca4c58b98e2d90ba70372f jdk9-b45 74eaf7ad986576c792df4dbff05eed63e5727695 jdk9-b46 e391de88e69b59d7c618387e3cf91032f6991ce9 jdk9-b47 +833051855168a973780fafeb6fc59e7370bcf400 jdk9-b48 From fa86b94fe6a914a8c8c5fd5f1adbfb084112ff31 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 28 Jan 2015 16:45:40 -0800 Subject: [PATCH 57/72] Added tag jdk9-b48 for changeset a5c172165b3b --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 2f346d3cdf5..aab4c7697f1 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -293,3 +293,4 @@ edc13d27dc871be57d7ca77eef77e6d04972fee2 jdk9-b43 e529374fbe526dbd668e5e98fc047b42b3bc6d33 jdk9-b45 64ca52b0bda8028636e4ccafbe1107befcdda47d jdk9-b46 6c17d648d03e4bf4729c3645f8db55d34115e0b7 jdk9-b47 +33e7e699804892c0496adf60ad67cc12855aeb61 jdk9-b48 From bdd8a4a4b9337a7d0fe2a94246e242106b7ddf5d Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 28 Jan 2015 16:45:45 -0800 Subject: [PATCH 58/72] Added tag jdk9-b48 for changeset 6d99e9b8dbe5 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index e5ebdf47f06..c5a3e91f84e 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -290,3 +290,4 @@ e336cbd8b15e959e70ed02f0f5e93fa76ebd4c07 jdk9-b41 9acaa4f57b0b9e3757a7b4576ca9418a75ea8287 jdk9-b45 efedac7f44ed41cea2b1038138047271f55aacba jdk9-b46 b641c14730ac05d9ec8b4f66e6fca3dc21adb403 jdk9-b47 +ebb2eb7f1aec78eb6d8cc4c96f018afa11093cde jdk9-b48 From b2b80fa1f7840d967af00439281fd54817cab517 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 28 Jan 2015 16:45:50 -0800 Subject: [PATCH 59/72] Added tag jdk9-b48 for changeset 6e2e298c50f1 --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index db208a84159..7a22bbd527e 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -290,3 +290,4 @@ de2ce70d907c9f227b802cea29285bece5194cd5 jdk9-b44 73bbdcf236b297a0c1b8875f2eeba65eaf7ade60 jdk9-b45 e272d9be5f90edb6bb6b40f7816ec85eec0f5dc2 jdk9-b46 230c139552501e612dd0d4423ac30f94c1201c0d jdk9-b47 +5b102fc29edf8b7eee7df208d8a8bba0e0a52f3a jdk9-b48 From a35131edd70b613b4bf4820049ecbfc4bb50b082 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 28 Jan 2015 16:45:51 -0800 Subject: [PATCH 60/72] Added tag jdk9-b48 for changeset 5f1e4deb8d30 --- nashorn/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/nashorn/.hgtags b/nashorn/.hgtags index f754a233071..76c29cdab83 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -281,3 +281,4 @@ dd7bbdf81a537106cfa9227d1a9a57849cb26b4d jdk9-b37 3c2bbeda038aef7061455fec604db7d8a342fac5 jdk9-b45 2ecf0a617f0f9af1ffd278a0c70e76f1946ce773 jdk9-b46 29046d42a95e5b9f105ab086a628bbd7f81c915d jdk9-b47 +f08660f30051ba0b38ad00e692979b37d107c9c4 jdk9-b48 From 4590abcd511be7983544e0494a30763d70348d48 Mon Sep 17 00:00:00 2001 From: Frank Yuan Date: Wed, 28 Jan 2015 22:49:58 -0800 Subject: [PATCH 61/72] 8051547: Convert JAXP function tests: javax.xml.validation.* to jtreg (testng) tests Reviewed-by: lancea, joehw --- .../validation/ptests/SchemaFactoryTest.java | 297 ++++++++++++++++++ .../ptests/TypeInfoProviderTest.java | 93 ++++++ .../ptests/ValidatorHandlerTest.java | 144 +++++++++ .../xml/validation/ptests/ValidatorTest.java | 207 ++++++++++++ .../xml/validation/xmlfiles/shiporder11.xml | 24 ++ .../xml/validation/xmlfiles/shiporder11.xsd | 51 +++ .../xml/validation/xmlfiles/shiporder12.xml | 24 ++ .../xml/validation/xmlfiles/shiporder12.xsd | 51 +++ .../javax/xml/validation/xmlfiles/test.xml | 5 + .../javax/xml/validation/xmlfiles/test.xsd | 11 + .../javax/xml/validation/xmlfiles/test1.xsd | 11 + .../xml/validation/ptests/MyErrorHandler.java | 40 +++ .../ptests/ValidationTestConst.java | 43 +++ 13 files changed, 1001 insertions(+) create mode 100644 jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/SchemaFactoryTest.java create mode 100644 jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/TypeInfoProviderTest.java create mode 100644 jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorHandlerTest.java create mode 100644 jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorTest.java create mode 100644 jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xml create mode 100644 jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xsd create mode 100644 jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xml create mode 100644 jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xsd create mode 100644 jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xml create mode 100644 jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xsd create mode 100644 jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test1.xsd create mode 100644 jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/MyErrorHandler.java create mode 100644 jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/ValidationTestConst.java diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/SchemaFactoryTest.java b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/SchemaFactoryTest.java new file mode 100644 index 00000000000..de285f21aa8 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/SchemaFactoryTest.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 1999, 2015, 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 javax.xml.validation.ptests; + +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +import static javax.xml.validation.ptests.ValidationTestConst.XML_DIR; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertSame; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; + +/* + * @summary Class containing the test cases for SchemaFactory + */ +@Test(singleThreaded = true) +public class SchemaFactoryTest { + + @BeforeClass + public void setup() throws SAXException, IOException, ParserConfigurationException { + sf = newSchemaFactory(); + + assertNotNull(sf); + + xsd1 = Files.readAllBytes(Paths.get(XML_DIR + "test.xsd")); + xsd2 = Files.readAllBytes(Paths.get(XML_DIR + "test1.xsd")); + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + DocumentBuilder db = dbf.newDocumentBuilder(); + xsdDoc1 = db.parse(newInputStream(xsd1)); + xsdDoc2 = db.parse(newInputStream(xsd2)); + + xml = Files.readAllBytes(Paths.get(XML_DIR + "test.xml")); + } + + @Test(expectedExceptions = SAXParseException.class) + public void testNewSchemaDefault() throws SAXException, IOException { + validate(sf.newSchema()); + } + + @Test + public void testNewSchemaWithFile() throws SAXException, IOException { + validate(sf.newSchema(new File(XML_DIR + "test.xsd"))); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNewSchemaWithNullFile() throws SAXException { + sf.newSchema((File) null); + } + + @DataProvider(name = "valid-source") + public Object[][] getValidSource() { + return new Object[][] { + { streamSource(xsd1) }, + { saxSource(xsd1) }, + { domSource(xsdDoc1) } }; + + } + + @Test(dataProvider = "valid-source") + public void testNewSchemaWithValidSource(Source schema) throws SAXException, IOException { + validate(sf.newSchema(schema)); + } + + @DataProvider(name = "invalid-source") + public Object[][] getInvalidSource() { + return new Object[][] { + { nullStreamSource() }, + { nullSaxSource() } }; + } + + @Test(dataProvider = "invalid-source", expectedExceptions = SAXParseException.class) + public void testNewSchemaWithInvalidSource(Source schema) throws SAXException { + sf.newSchema(schema); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNewSchemaWithNullSource() throws SAXException { + sf.newSchema((Source)null); + } + + @DataProvider(name = "valid-sources") + public Object[][] getValidSources() { + return new Object[][] { + { streamSource(xsd1), streamSource(xsd2) }, + { saxSource(xsd1), saxSource(xsd2) }, + { domSource(xsdDoc1), domSource(xsdDoc2) } }; + + } + + @Test(dataProvider = "valid-sources") + public void testNewSchemaWithValidSourceArray(Source schema1, Source schema2) throws SAXException, IOException { + validate(sf.newSchema(new Source[] { schema1, schema2 })); + } + + @DataProvider(name = "invalid-sources") + public Object[][] getInvalidSources() { + return new Object[][] { + { streamSource(xsd1), nullStreamSource() }, + { nullStreamSource(), nullStreamSource() }, + { saxSource(xsd1), nullSaxSource() }, + { nullSaxSource(), nullSaxSource() } }; + } + + @Test(dataProvider = "invalid-sources", expectedExceptions = SAXParseException.class) + public void testNewSchemaWithInvalidSourceArray(Source schema1, Source schema2) throws SAXException { + sf.newSchema(new Source[] { schema1, schema2 }); + } + + @DataProvider(name = "null-sources") + public Object[][] getNullSources() { + return new Object[][] { + { new Source[] { domSource(xsdDoc1), null } }, + { new Source[] { null, null } }, + { null } }; + + } + + @Test(dataProvider = "null-sources", expectedExceptions = NullPointerException.class) + public void testNewSchemaWithNullSourceArray(Source[] schemas) throws SAXException { + sf.newSchema(schemas); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNewSchemaWithNullUrl() throws SAXException { + sf.newSchema((URL) null); + } + + + @Test + public void testErrorHandler() { + SchemaFactory sf = newSchemaFactory(); + assertNull(sf.getErrorHandler(), "When SchemaFactory is created, initially ErrorHandler should not be set."); + + ErrorHandler handler = new MyErrorHandler(); + sf.setErrorHandler(handler); + assertSame(sf.getErrorHandler(), handler); + + sf.setErrorHandler(null); + assertNull(sf.getErrorHandler()); + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testGetUnrecognizedProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + sf.getProperty(UNRECOGNIZED_NAME); + + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testSetUnrecognizedProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + sf.setProperty(UNRECOGNIZED_NAME, "test"); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testGetNullProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + assertNotNull(sf); + sf.getProperty(null); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testSetNullProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + assertNotNull(sf); + sf.setProperty(null, "test"); + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testGetUnrecognizedFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + sf.getFeature(UNRECOGNIZED_NAME); + + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testSetUnrecognizedFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + sf.setFeature(UNRECOGNIZED_NAME, true); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testGetNullFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + assertNotNull(sf); + sf.getFeature(null); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testSetNullFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + assertNotNull(sf); + sf.setFeature(null, true); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testInvalidSchemaLanguage() { + final String INVALID_SCHEMA_LANGUAGE = "http://relaxng.org/ns/structure/1.0"; + SchemaFactory.newInstance(INVALID_SCHEMA_LANGUAGE); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNullSchemaLanguage() { + SchemaFactory.newInstance(null); + } + + private void validate(Schema schema) throws SAXException, IOException { + schema.newValidator().validate(new StreamSource(new ByteArrayInputStream(xml))); + } + private InputStream newInputStream(byte[] xsd) { + return new ByteArrayInputStream(xsd); + } + + private Source streamSource(byte[] xsd) { + return new StreamSource(newInputStream(xsd)); + } + + private Source nullStreamSource() { + return new StreamSource((InputStream) null); + } + + private Source saxSource(byte[] xsd) { + return new SAXSource(new InputSource(newInputStream(xsd))); + } + + private Source nullSaxSource() { + return new SAXSource(new InputSource((InputStream) null)); + } + + private Source domSource(Document xsdDoc) { + return new DOMSource(xsdDoc); + } + + private SchemaFactory newSchemaFactory() { + return SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); + } + + private static final String UNRECOGNIZED_NAME = "http://xml.org/sax/features/namespace-prefixes"; + + private SchemaFactory sf; + private byte[] xsd1; + private byte[] xsd2; + private Document xsdDoc1; + private Document xsdDoc2; + private byte[] xml; +} diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/TypeInfoProviderTest.java b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/TypeInfoProviderTest.java new file mode 100644 index 00000000000..d34c708bc90 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/TypeInfoProviderTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1999, 2015, 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 javax.xml.validation.ptests; + +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +import static javax.xml.validation.ptests.ValidationTestConst.XML_DIR; +import static jaxp.library.JAXPTestUtilities.filenameToURL; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.TypeInfoProvider; +import javax.xml.validation.ValidatorHandler; + +import jaxp.library.JAXPFileBaseTest; + +import org.testng.annotations.Test; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +/* + * @summary test ValidatorHandler.getTypeInfoProvider() + */ +public class TypeInfoProviderTest extends JAXPFileBaseTest { + + private ValidatorHandler validatorHandler; + + @Test + public void test() throws SAXException, ParserConfigurationException, IOException { + + SchemaFactory sf = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); + Schema schema = sf.newSchema(new File(XML_DIR + "shiporder11.xsd")); + validatorHandler = schema.newValidatorHandler(); + MyDefaultHandler myDefaultHandler = new MyDefaultHandler(); + validatorHandler.setContentHandler(myDefaultHandler); + + InputSource is = new InputSource(filenameToURL(XML_DIR + "shiporder11.xml")); + + SAXParserFactory parserFactory = SAXParserFactory.newInstance(); + parserFactory.setNamespaceAware(true); + XMLReader xmlReader = parserFactory.newSAXParser().getXMLReader(); + xmlReader.setContentHandler(validatorHandler); + xmlReader.parse(is); + + } + + private class MyDefaultHandler extends DefaultHandler { + + public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { + TypeInfoProvider typeInfoProvider = validatorHandler.getTypeInfoProvider(); + int index = atts.getIndex("orderid"); + if (index != -1) { + System.out.println(" Index " + index); + System.out.println(" ElementType " + typeInfoProvider.getElementTypeInfo().getTypeName()); + assertEquals(typeInfoProvider.getAttributeTypeInfo(index).getTypeName(), "string"); + assertTrue(typeInfoProvider.isSpecified(index)); + assertFalse(typeInfoProvider.isIdAttribute(index)); + } + + } + + } +} diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorHandlerTest.java b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorHandlerTest.java new file mode 100644 index 00000000000..3b48a21203f --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorHandlerTest.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 1999, 2015, 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 javax.xml.validation.ptests; + +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +import static javax.xml.validation.ptests.ValidationTestConst.XML_DIR; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.io.File; + +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.ValidatorHandler; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.xml.sax.ContentHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.helpers.DefaultHandler; + +/* + * @summary Class containing the test cases for ValidatorHandler API + */ +public class ValidatorHandlerTest { + @BeforeClass + public void setup() throws SAXException { + schema = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI).newSchema(new File(XML_DIR + "test.xsd")); + + assertNotNull(schema); + } + + @Test + public void testErrorHandler() { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertNull(validatorHandler.getErrorHandler(), "When ValidatorHandler is created, initially ErrorHandler should not be set."); + + ErrorHandler handler = new MyErrorHandler(); + validatorHandler.setErrorHandler(handler); + assertSame(validatorHandler.getErrorHandler(), handler); + + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testGetUnrecognizedProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + validatorHandler.getProperty(FEATURE_NAME); + + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testSetUnrecognizedProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + validatorHandler.setProperty(FEATURE_NAME, "test"); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testGetNullProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertNotNull(validatorHandler); + validatorHandler.getProperty(null); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testSetNullProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertNotNull(validatorHandler); + validatorHandler.setProperty(null, "test"); + } + + public void testFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertFalse(validatorHandler.getFeature(FEATURE_NAME), "The feature should be false by default."); + + validatorHandler.setFeature(FEATURE_NAME, true); + assertTrue(validatorHandler.getFeature(FEATURE_NAME), "The feature should be false by default."); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testGetNullFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertNotNull(validatorHandler); + validatorHandler.getFeature(null); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testSetNullFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertNotNull(validatorHandler); + validatorHandler.setFeature(null, true); + } + + @Test + public void testContentHandler() { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertNull(validatorHandler.getContentHandler(), "When ValidatorHandler is created, initially ContentHandler should not be set."); + + ContentHandler handler = new DefaultHandler(); + validatorHandler.setContentHandler(handler); + assertSame(validatorHandler.getContentHandler(), handler); + + validatorHandler.setContentHandler(null); + assertNull(validatorHandler.getContentHandler()); + + } + + private ValidatorHandler getValidatorHandler() { + return schema.newValidatorHandler(); + } + + private static final String FEATURE_NAME = "http://xml.org/sax/features/namespace-prefixes"; + + private Schema schema; + +} diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorTest.java b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorTest.java new file mode 100644 index 00000000000..c455f070694 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 1999, 2015, 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 javax.xml.validation.ptests; + +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +import static javax.xml.validation.ptests.ValidationTestConst.XML_DIR; +import static jaxp.library.JAXPTestUtilities.filenameToURL; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertSame; + +import java.io.File; +import java.io.IOException; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import jaxp.library.JAXPFileBaseTest; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.helpers.DefaultHandler; + +/* + * @summary Class containing the test cases for Validator API + */ +public class ValidatorTest extends JAXPFileBaseTest { + + @BeforeClass + public void setup() throws SAXException, IOException, ParserConfigurationException { + schema = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI).newSchema(new File(XML_DIR + "test.xsd")); + + assertNotNull(schema); + + xmlFileUri = filenameToURL(XML_DIR + "test.xml"); + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + xmlDoc = dbf.newDocumentBuilder().parse(xmlFileUri); + } + + @Test + public void testValidateStreamSource() throws SAXException, IOException { + Validator validator = getValidator(); + validator.setErrorHandler(new MyErrorHandler()); + validator.validate(getStreamSource()); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testValidateNullSource() throws SAXException, IOException { + Validator validator = getValidator(); + assertNotNull(validator); + validator.validate(null); + } + + @Test + public void testErrorHandler() { + Validator validator = getValidator(); + assertNull(validator.getErrorHandler(), "When Validator is created, initially ErrorHandler should not be set."); + + ErrorHandler mh = new MyErrorHandler(); + validator.setErrorHandler(mh); + assertSame(validator.getErrorHandler(), mh); + + } + + @DataProvider(name = "source-result") + public Object[][] getSourceAndResult() { + return new Object[][] { + { getStreamSource(), null }, + { getSAXSource(), getSAXResult() }, + { getDOMSource(), getDOMResult() }, + { getSAXSource(), null }, + { getDOMSource(), null } }; + } + + @Test(dataProvider = "source-result") + public void testValidateWithResult(Source source, Result result) throws SAXException, IOException { + Validator validator = getValidator(); + validator.validate(source, result); + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testGetUnrecognizedProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + validator.getProperty(UNRECOGNIZED_NAME); + + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testSetUnrecognizedProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + validator.setProperty(UNRECOGNIZED_NAME, "test"); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testGetNullProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + assertNotNull(validator); + validator.getProperty(null); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testSetNullProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + assertNotNull(validator); + validator.setProperty(null, "test"); + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testGetUnrecognizedFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + validator.getFeature(UNRECOGNIZED_NAME); + + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testSetUnrecognizedFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + validator.setFeature(UNRECOGNIZED_NAME, true); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testGetNullFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + assertNotNull(validator); + validator.getFeature(null); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testSetNullFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + assertNotNull(validator); + validator.setFeature(null, true); + } + + private Validator getValidator() { + return schema.newValidator(); + } + + private Source getStreamSource() { + return new StreamSource(xmlFileUri); + } + + private Source getSAXSource() { + return new SAXSource(new InputSource(xmlFileUri)); + } + + private Result getSAXResult() { + SAXResult saxResult = new SAXResult(); + saxResult.setHandler(new DefaultHandler()); + return saxResult; + } + + private Source getDOMSource() { + return new DOMSource(xmlDoc); + } + + private Result getDOMResult() { + return new DOMResult(); + } + + private static final String UNRECOGNIZED_NAME = "http://xml.org/sax/features/namespace-prefixes"; + private String xmlFileUri; + private Schema schema; + private Document xmlDoc; + +} diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xml b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xml new file mode 100644 index 00000000000..0a00dbdaae0 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xml @@ -0,0 +1,24 @@ + + + +John Smith + +Ola Nordmann +
    Langgt 23
    +4000 Stavanger +Norway +
    + +Empire Burlesque +Special Edition +1 +10.90 + + +Hide your heart +1 +9.90 + +
    \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xsd b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xsd new file mode 100644 index 00000000000..7281dbd9698 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xsd @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xml b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xml new file mode 100644 index 00000000000..0a00dbdaae0 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xml @@ -0,0 +1,24 @@ + + + +John Smith + +Ola Nordmann +
    Langgt 23
    +4000 Stavanger +Norway +
    + +Empire Burlesque +Special Edition +1 +10.90 + + +Hide your heart +1 +9.90 + +
    \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xsd b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xsd new file mode 100644 index 00000000000..7281dbd9698 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xsd @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xml b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xml new file mode 100644 index 00000000000..8ad28618d01 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xml @@ -0,0 +1,5 @@ + + + John +444-121-3434 + diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xsd b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xsd new file mode 100644 index 00000000000..1671283691c --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xsd @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test1.xsd b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test1.xsd new file mode 100644 index 00000000000..9f172d23639 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test1.xsd @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/MyErrorHandler.java b/jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/MyErrorHandler.java new file mode 100644 index 00000000000..1efbf95749f --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/MyErrorHandler.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, 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 javax.xml.validation.ptests; + +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXParseException; + +class MyErrorHandler implements ErrorHandler { + public void error(SAXParseException exception) throws SAXParseException { + throw exception; + } + + public void warning(SAXParseException exception) throws SAXParseException { + throw exception; + } + + public void fatalError(SAXParseException exception) throws SAXParseException { + throw exception; + } +} diff --git a/jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/ValidationTestConst.java b/jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/ValidationTestConst.java new file mode 100644 index 00000000000..50f4c86d0e5 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/ValidationTestConst.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, 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 javax.xml.validation.ptests; + +import static jaxp.library.JAXPTestUtilities.FILE_SEP; +import static jaxp.library.JAXPTestUtilities.getPathByClassName; + +/** + * This class defines the path constant + */ +public class ValidationTestConst { + /** + * XML source file directory. + */ + public static final String XML_DIR = getPathByClassName(ValidationTestConst.class, + ".." + FILE_SEP + "xmlfiles"); + + /** + * Golden validation files directory. + */ + public static final String GOLDEN_DIR = getPathByClassName(ValidationTestConst.class, + ".." + FILE_SEP + "xmlfiles" + FILE_SEP + "out"); +} From 57d42b897c38dc38fb73ec5e20fbc005a3c47258 Mon Sep 17 00:00:00 2001 From: Rob McKenna Date: Thu, 29 Jan 2015 14:59:42 +0000 Subject: [PATCH 62/72] 8067680: (sctp) Possible race initializing native IDs Reviewed-by: chegar, rriggs --- jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c b/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c index db97c948ee6..6a5e2cbbb8c 100644 --- a/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c +++ b/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c @@ -316,11 +316,12 @@ void initializeISA if (isaCls == 0) { jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress"); CHECK_NULL(c); + isaCtrID = (*env)->GetMethodID(env, c, "", + "(Ljava/net/InetAddress;I)V"); + CHECK_NULL(isaCtrID); isaCls = (*env)->NewGlobalRef(env, c); CHECK_NULL(isaCls); (*env)->DeleteLocalRef(env, c); - isaCtrID = (*env)->GetMethodID(env, isaCls, "", - "(Ljava/net/InetAddress;I)V"); } } From 60fdd0dceb20da5ae874176118d91628d9d7b1cf Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Thu, 29 Jan 2015 20:45:30 +0000 Subject: [PATCH 63/72] 8067105: Socket returned by ServerSocket.accept() is inherited by child process on Windows Reviewed-by: alanb, igerasim --- .../native/libnet/DualStackPlainSocketImpl.c | 2 + .../native/libnet/TwoStacksPlainSocketImpl.c | 1 + .../libnio/ch/ServerSocketChannelImpl.c | 1 + .../net/ServerSocket/AcceptInheritHandle.java | 147 ++++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 jdk/test/java/net/ServerSocket/AcceptInheritHandle.java diff --git a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c index 3ea09c32888..40c0f7150f6 100644 --- a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c +++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c @@ -296,6 +296,8 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0 return -1; } + SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); + ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port); (*env)->SetObjectArrayElement(env, isaa, 0, isa); diff --git a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c index c4686e0fe78..b4f9f140789 100644 --- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c +++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c @@ -699,6 +699,7 @@ Java_java_net_TwoStacksPlainSocketImpl_socketAccept(JNIEnv *env, jobject this, } return; } + SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, 0); (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, fd); if (him.him.sa_family == AF_INET) { diff --git a/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c b/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c index 30d6d641645..8cd94eadaa9 100644 --- a/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c +++ b/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c @@ -105,6 +105,7 @@ Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jobject this, return IOS_THROWN; } + SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); (*env)->SetIntField(env, newfdo, fd_fdID, newfd); remote_ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, (int *)&remote_port); CHECK_NULL_RETURN(remote_ia, IOS_THROWN); diff --git a/jdk/test/java/net/ServerSocket/AcceptInheritHandle.java b/jdk/test/java/net/ServerSocket/AcceptInheritHandle.java new file mode 100644 index 00000000000..ce175f2f490 --- /dev/null +++ b/jdk/test/java/net/ServerSocket/AcceptInheritHandle.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8067105 + * @summary Socket returned by ServerSocket.accept() is inherited by child process on Windows + * @author Chris Hegarty + */ + +import java.io.*; +import java.net.*; +import java.nio.channels.ServerSocketChannel; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +public class AcceptInheritHandle { + + enum ServerSocketProducer { + JAVA_NET(() -> { + try { + return new ServerSocket(); } + catch(IOException x) { + throw new UncheckedIOException(x); + } + }), + NIO_CHANNELS(() -> { + try { + return ServerSocketChannel.open().socket(); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + + final Supplier supplier; + ServerSocketProducer(Supplier supplier) { + this.supplier = supplier; + } + Supplier supplier () { return supplier; } + } + + static final String JAVA = System.getProperty("java.home") + + File.separator + "bin" + File.separator + "java"; + + static final String CLASSPATH = System.getProperty("java.class.path"); + + public static void main(String[] args) throws Exception { + if (args.length == 1) + server(ServerSocketProducer.valueOf(args[0])); + else + mainEntry(); + } + + static void mainEntry() throws Exception { + testJavaNetServerSocket(); + testNioServerSocketChannel(); + } + + static void testJavaNetServerSocket() throws Exception { + test(ServerSocketProducer.JAVA_NET); + test(ServerSocketProducer.JAVA_NET, "-Djava.net.preferIPv4Stack=true"); + } + static void testNioServerSocketChannel() throws Exception { + test(ServerSocketProducer.NIO_CHANNELS); + } + + static void test(ServerSocketProducer ssp, String... sysProps) throws Exception { + System.out.println("\nStarting test for " + ssp.name()); + + List commands = new ArrayList<>(); + commands.add(JAVA); + for (String prop : sysProps) + commands.add(prop); + commands.add("-cp"); + commands.add(CLASSPATH); + commands.add("AcceptInheritHandle"); + commands.add(ssp.name()); + + System.out.println("Executing: "+ commands); + ProcessBuilder pb = new ProcessBuilder(commands); + pb.redirectError(ProcessBuilder.Redirect.INHERIT); + Process serverProcess = pb.start(); + DataInputStream dis = new DataInputStream(serverProcess.getInputStream()); + + int port = dis.readInt(); + System.out.println("Server process listening on " + port + ", connecting..."); + + Socket socket = new Socket("localhost", port); + String s = dis.readUTF(); + System.out.println("Server process said " + s); + + serverProcess.destroy(); + serverProcess.waitFor(30, TimeUnit.SECONDS); + System.out.println("serverProcess exitCode:" + serverProcess.exitValue()); + + try { + socket.setSoTimeout(10 * 1000); + socket.getInputStream().read(); + } catch (SocketTimeoutException x) { + // failed + throw new RuntimeException("Failed: should get reset, not " + x); + } catch (SocketException x) { + System.out.println("Expected:" + x); + } + } + + static void server(ServerSocketProducer producer) throws Exception { + try (ServerSocket ss = producer.supplier().get()) { + ss.bind(new InetSocketAddress(0)); + int port = ss.getLocalPort(); + DataOutputStream dos = new DataOutputStream(System.out); + dos.writeInt(port); + dos.flush(); + + ss.accept(); // do not close + + Runtime.getRuntime().exec("sleep 20"); + Thread.sleep(3 * 1000); + + dos.writeUTF("kill me!"); + dos.flush(); + Thread.sleep(30 * 1000); + } + } +} From 6b95a91213ebfaf8d3b58b57d03c0e480b7dbb45 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Thu, 29 Jan 2015 14:43:19 -0800 Subject: [PATCH 64/72] 8071617: move pathToURLs from javac.file.Locations to javadoc.DocletInvoker Reviewed-by: ksrini --- .../com/sun/tools/javac/file/Locations.java | 41 ------------ .../com/sun/tools/javadoc/DocletInvoker.java | 62 ++++++++++++++++--- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java index f8011f3c226..ce34dcabb26 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java @@ -783,45 +783,4 @@ public class Locations { && (n.endsWith(".jar") || n.endsWith(".zip")); } - /** - * Utility method for converting a search path string to an array of directory and JAR file - * URLs. - * - * Note that this method is called by the DocletInvoker. - * - * @param path the search path string - * @return the resulting array of directory and JAR file URLs - */ - public static URL[] pathToURLs(String path) { - java.util.List urls = new ArrayList<>(); - for (String s: path.split(Pattern.quote(File.pathSeparator))) { - if (!s.isEmpty()) { - URL url = fileToURL(Paths.get(s)); - if (url != null) { - urls.add(url); - } - } - } - return urls.toArray(new URL[urls.size()]); - } - - /** - * Returns the directory or JAR file URL corresponding to the specified local file name. - * - * @param file the Path object - * @return the resulting directory or JAR file URL, or null if unknown - */ - private static URL fileToURL(Path file) { - Path p; - try { - p = file.toRealPath(); - } catch (IOException e) { - p = file.toAbsolutePath(); - } - try { - return p.normalize().toUri().toURL(); - } catch (MalformedURLException e) { - return null; - } - } } diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/DocletInvoker.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/DocletInvoker.java index f12ffe951c0..b4326531ca4 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/DocletInvoker.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/DocletInvoker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, 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 @@ -26,19 +26,25 @@ package com.sun.tools.javadoc; import java.io.File; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.regex.Pattern; import javax.tools.DocumentationTool; import javax.tools.JavaFileManager; import com.sun.javadoc.*; -import com.sun.tools.javac.file.Locations; import com.sun.tools.javac.util.ClientCodeException; import com.sun.tools.javac.util.List; + import static com.sun.javadoc.LanguageVersion.*; @@ -108,7 +114,7 @@ public class DocletInvoker { cpString = appendPath(System.getProperty("env.class.path"), cpString); cpString = appendPath(System.getProperty("java.class.path"), cpString); cpString = appendPath(docletPath, cpString); - URL[] urls = Locations.pathToURLs(cpString); + URL[] urls = pathToURLs(cpString); if (docletParentClassLoader == null) appClassLoader = new URLClassLoader(urls, getDelegationClassLoader(docletClassName)); else @@ -191,7 +197,7 @@ public class DocletInvoker { return false; } if (retVal instanceof Boolean) { - return ((Boolean)retVal).booleanValue(); + return ((Boolean)retVal); } else { messager.error(Messager.NOPOS, "main.must_return_boolean", docletClassName, methodName); @@ -215,7 +221,7 @@ public class DocletInvoker { return -1; } if (retVal instanceof Integer) { - return ((Integer)retVal).intValue(); + return ((Integer)retVal); } else { messager.error(Messager.NOPOS, "main.must_return_int", docletClassName, methodName); @@ -240,7 +246,7 @@ public class DocletInvoker { return false; } if (retVal instanceof Boolean) { - return ((Boolean)retVal).booleanValue(); + return ((Boolean)retVal); } else { messager.error(Messager.NOPOS, "main.must_return_boolean", docletClassName, methodName); @@ -326,11 +332,53 @@ public class DocletInvoker { } else { messager.error(Messager.NOPOS, "main.exception_thrown", docletClassName, methodName, exc.toString()); - exc.getTargetException().printStackTrace(); + exc.getTargetException().printStackTrace(System.err); } throw new DocletInvokeException(); } finally { Thread.currentThread().setContextClassLoader(savedCCL); } } + + /** + * Utility method for converting a search path string to an array of directory and JAR file + * URLs. + * + * Note that this method is called by the DocletInvoker. + * + * @param path the search path string + * @return the resulting array of directory and JAR file URLs + */ + private static URL[] pathToURLs(String path) { + java.util.List urls = new ArrayList<>(); + for (String s: path.split(Pattern.quote(File.pathSeparator))) { + if (!s.isEmpty()) { + URL url = fileToURL(Paths.get(s)); + if (url != null) { + urls.add(url); + } + } + } + return urls.toArray(new URL[urls.size()]); + } + + /** + * Returns the directory or JAR file URL corresponding to the specified local file name. + * + * @param file the Path object + * @return the resulting directory or JAR file URL, or null if unknown + */ + private static URL fileToURL(Path file) { + Path p; + try { + p = file.toRealPath(); + } catch (IOException e) { + p = file.toAbsolutePath(); + } + try { + return p.normalize().toUri().toURL(); + } catch (MalformedURLException e) { + return null; + } + } } From 76ace03a9eb28b9b32278de312a815ce1c695c54 Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Thu, 29 Jan 2015 14:49:15 -0800 Subject: [PATCH 65/72] 8068578: test/java/io/Serializable/subclassGC/SubclassGC.java assumes app class loader is a URLClassLoader Reviewed-by: alanb --- jdk/test/java/io/Serializable/subclassGC/SubclassGC.java | 5 +++-- jdk/test/java/io/Serializable/subclassGC/security.policy | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/jdk/test/java/io/Serializable/subclassGC/SubclassGC.java b/jdk/test/java/io/Serializable/subclassGC/SubclassGC.java index 323a05e8410..ae16712c97f 100644 --- a/jdk/test/java/io/Serializable/subclassGC/SubclassGC.java +++ b/jdk/test/java/io/Serializable/subclassGC/SubclassGC.java @@ -50,8 +50,9 @@ public class SubclassGC { } ClassLoader systemLoader = ClassLoader.getSystemClassLoader(); - ClassLoader loader = new URLClassLoader(((URLClassLoader) systemLoader).getURLs(), - systemLoader.getParent()); + URL testClassesURL = new File(System.getProperty("test.classes")).toURI().toURL(); + ClassLoader loader = new URLClassLoader(new URL[] { testClassesURL } , + systemLoader.getParent()); Class cl = Class.forName(SubclassOfOOS.class.getName(), false, loader).asSubclass(ObjectOutputStream.class); diff --git a/jdk/test/java/io/Serializable/subclassGC/security.policy b/jdk/test/java/io/Serializable/subclassGC/security.policy index 894df4cd2dd..a3ef804b37a 100644 --- a/jdk/test/java/io/Serializable/subclassGC/security.policy +++ b/jdk/test/java/io/Serializable/subclassGC/security.policy @@ -2,5 +2,7 @@ grant { permission java.lang.RuntimePermission "createClassLoader"; permission java.lang.RuntimePermission "getClassLoader"; + permission java.util.PropertyPermission "test.classes", "read"; + permission java.io.FilePermission "<>", "read"; }; From 0841b6a90ed3da376ed9ae8caefdcdb6f2ec4bdd Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 29 Jan 2015 15:14:44 -0800 Subject: [PATCH 66/72] 8071434: doc updates for java.lang.Object Reviewed-by: rriggs --- .../share/classes/java/lang/Object.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/Object.java b/jdk/src/java.base/share/classes/java/lang/Object.java index 04ca33153d6..8ad28c4a595 100644 --- a/jdk/src/java.base/share/classes/java/lang/Object.java +++ b/jdk/src/java.base/share/classes/java/lang/Object.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2015, 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 @@ -86,12 +86,11 @@ public class Object { * for unequal objects may improve the performance of hash tables. * *

    - * As much as is reasonably practical, the hashCode method defined by - * class {@code Object} does return distinct integers for distinct - * objects. (This is typically implemented by converting the internal - * address of the object into an integer, but this implementation - * technique is not required by the - * Java™ programming language.) + * As much as is reasonably practical, the hashCode method defined + * by class {@code Object} does return distinct integers for + * distinct objects. (The hashCode may or may not be implemented + * as some function of an object's memory address at some point + * in time.) * * @return a hash code value for this object. * @see java.lang.Object#equals(java.lang.Object) @@ -344,10 +343,12 @@ public class Object { * ... // Perform action appropriate to condition * } * - * (For more information on this topic, see Section 3.2.3 in Doug Lea's - * "Concurrent Programming in Java (Second Edition)" (Addison-Wesley, - * 2000), or Item 50 in Joshua Bloch's "Effective Java Programming - * Language Guide" (Addison-Wesley, 2001). + * + * (For more information on this topic, see section 14.2, + * Condition Queues, in Brian Goetz and others' "Java Concurrency + * in Practice" (Addison-Wesley, 2006) or Item 69 in Joshua + * Bloch's "Effective Java (Second Edition)" (Addison-Wesley, + * 2008). * *

    If the current thread is {@linkplain java.lang.Thread#interrupt() * interrupted} by any thread before or while it is waiting, then an From 51e2269c61a6f5ffd08a6e08b4606df5e507fd7d Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 29 Jan 2015 16:16:35 -0800 Subject: [PATCH 67/72] 8071959: java.lang.Object uses implicit default constructor Reviewed-by: lancea --- jdk/src/java.base/share/classes/java/lang/Object.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jdk/src/java.base/share/classes/java/lang/Object.java b/jdk/src/java.base/share/classes/java/lang/Object.java index 8ad28c4a595..2eeac24a688 100644 --- a/jdk/src/java.base/share/classes/java/lang/Object.java +++ b/jdk/src/java.base/share/classes/java/lang/Object.java @@ -41,6 +41,11 @@ public class Object { registerNatives(); } + /** + * Constructs a new object. + */ + public Object() {} + /** * Returns the runtime class of this {@code Object}. The returned * {@code Class} object is the object that is locked by {@code From 82418d4c815334aaad85128b4a4b7bdae3407460 Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Wed, 5 Jul 2017 20:16:24 +0200 Subject: [PATCH 68/72] Added tag jdk9-b48 for changeset b2f9702efbe9 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 8ad989563ae..f496bfd1d5d 100644 --- a/.hgtags +++ b/.hgtags @@ -290,3 +290,4 @@ abbfccd659b91a7bb815d5e36fed635dcdd40f31 jdk9-b44 bfc24ae2b900187585079bb11e66e459d1e525fe jdk9-b45 722378bc599e38d9a1dd484de30f10dfd7b21438 jdk9-b46 8327024a99559982b848e9c2191da9c0bf8838fd jdk9-b47 +b2f9702efbe95527ea3a991474fda23987ff1c5c jdk9-b48 From c2fe1ca4702f90cdb5f046acf28bfd7e4e9382e9 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 30 Jan 2015 10:23:45 -0800 Subject: [PATCH 69/72] 8067669: Documentation for methods in Number incomplete regarding too large values Remove statments about rounding and truncation from the *Valud() methods Reviewed-by: rriggs, darcy, alundblad --- .../share/classes/java/lang/Number.java | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/Number.java b/jdk/src/java.base/share/classes/java/lang/Number.java index b89ed7190f0..019ed9c56c3 100644 --- a/jdk/src/java.base/share/classes/java/lang/Number.java +++ b/jdk/src/java.base/share/classes/java/lang/Number.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2015, 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 @@ -37,7 +37,7 @@ package java.lang; * * For platform classes, the conversion is often analogous to a * narrowing primitive conversion or a widening primitive conversion - * as defining in The Java™ Language Specification + * as defined in The Java™ Language Specification * for converting between primitive types. Therefore, conversions may * lose information about the overall magnitude of a numeric value, may * lose precision, and may even return a result of a different sign @@ -54,8 +54,7 @@ package java.lang; */ public abstract class Number implements java.io.Serializable { /** - * Returns the value of the specified number as an {@code int}, - * which may involve rounding or truncation. + * Returns the value of the specified number as an {@code int}. * * @return the numeric value represented by this object after conversion * to type {@code int}. @@ -63,8 +62,7 @@ public abstract class Number implements java.io.Serializable { public abstract int intValue(); /** - * Returns the value of the specified number as a {@code long}, - * which may involve rounding or truncation. + * Returns the value of the specified number as a {@code long}. * * @return the numeric value represented by this object after conversion * to type {@code long}. @@ -72,8 +70,7 @@ public abstract class Number implements java.io.Serializable { public abstract long longValue(); /** - * Returns the value of the specified number as a {@code float}, - * which may involve rounding. + * Returns the value of the specified number as a {@code float}. * * @return the numeric value represented by this object after conversion * to type {@code float}. @@ -81,8 +78,7 @@ public abstract class Number implements java.io.Serializable { public abstract float floatValue(); /** - * Returns the value of the specified number as a {@code double}, - * which may involve rounding. + * Returns the value of the specified number as a {@code double}. * * @return the numeric value represented by this object after conversion * to type {@code double}. @@ -90,8 +86,7 @@ public abstract class Number implements java.io.Serializable { public abstract double doubleValue(); /** - * Returns the value of the specified number as a {@code byte}, - * which may involve rounding or truncation. + * Returns the value of the specified number as a {@code byte}. * *

    This implementation returns the result of {@link #intValue} cast * to a {@code byte}. @@ -105,8 +100,7 @@ public abstract class Number implements java.io.Serializable { } /** - * Returns the value of the specified number as a {@code short}, - * which may involve rounding or truncation. + * Returns the value of the specified number as a {@code short}. * *

    This implementation returns the result of {@link #intValue} cast * to a {@code short}. From 2a8d5c46e1ccc4e6b9e0e5e5d0d6edc50b6d316b Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 30 Jan 2015 12:56:12 -0800 Subject: [PATCH 70/72] 6880737: (fs) FileLock constructors don't throw NPE if the channel argument is null Throw IllegalArgumentException if the channel parameter is null Reviewed-by: alanb --- .../classes/java/nio/channels/FileLock.java | 3 + .../FileLock/FileLockConstructor.java | 169 ++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 jdk/test/java/nio/channels/FileLock/FileLockConstructor.java diff --git a/jdk/src/java.base/share/classes/java/nio/channels/FileLock.java b/jdk/src/java.base/share/classes/java/nio/channels/FileLock.java index 156071c99e7..73e351126ca 100644 --- a/jdk/src/java.base/share/classes/java/nio/channels/FileLock.java +++ b/jdk/src/java.base/share/classes/java/nio/channels/FileLock.java @@ -26,6 +26,7 @@ package java.nio.channels; import java.io.IOException; +import java.util.Objects; /** * A token representing a lock on a region of a file. @@ -147,6 +148,7 @@ public abstract class FileLock implements AutoCloseable { protected FileLock(FileChannel channel, long position, long size, boolean shared) { + Objects.requireNonNull(channel, "Null channel"); if (position < 0) throw new IllegalArgumentException("Negative position"); if (size < 0) @@ -185,6 +187,7 @@ public abstract class FileLock implements AutoCloseable { protected FileLock(AsynchronousFileChannel channel, long position, long size, boolean shared) { + Objects.requireNonNull(channel, "Null channel"); if (position < 0) throw new IllegalArgumentException("Negative position"); if (size < 0) diff --git a/jdk/test/java/nio/channels/FileLock/FileLockConstructor.java b/jdk/test/java/nio/channels/FileLock/FileLockConstructor.java new file mode 100644 index 00000000000..4655ebf80e9 --- /dev/null +++ b/jdk/test/java/nio/channels/FileLock/FileLockConstructor.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2015, 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. + */ + +import java.io.File; +import java.io.IOException; +import java.nio.channels.AsynchronousFileChannel; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.file.StandardOpenOption; + +/* + * @test + * @bug 6880737 + * @summary Test FileLock constructor parameter validation. + */ +public class FileLockConstructor { + public static void main(String[] args) throws IOException { + FileLock fileLock = null; + int failures = 0; + + // null FileChannel + boolean exceptionThrown = false; + try { + fileLock = new FileLockSub((FileChannel)null, 0, 0, false); + } catch (NullPointerException npe) { + exceptionThrown = true; + } + if (!exceptionThrown) { + System.err.println("FileLock constructor did not throw NPE for null FileChannel"); + failures++; + } + + // null AsynchronousFileChannel + exceptionThrown = false; + try { + fileLock = new FileLockSub((AsynchronousFileChannel)null, 0, 0, true); + } catch (NullPointerException npe) { + exceptionThrown = true; + } + if (!exceptionThrown) { + System.err.println("FileLock constructor did not throw NPE for null AsynchronousFileChannel"); + failures++; + } + + // create temporary file + File tmpFile = File.createTempFile("FileLock", "tmp"); + tmpFile.deleteOnExit(); + + // position and size preconditions + long[][] posAndSize = new long[][] { + {0, 42}, // valid + {-1, 42}, // invalid: position < 0 + {0, -1}, // invalid: size < 0 + {Long.MAX_VALUE, 1} // invalid: position + size < 0 + }; + + // test position and size preconditions for FileChannel case + try (FileChannel syncChannel = FileChannel.open(tmpFile.toPath(), + StandardOpenOption.READ, StandardOpenOption.WRITE)) { + + for (int i = 0; i < posAndSize.length; i++) { + boolean preconditionsHold = i == 0; + exceptionThrown = false; + try { + fileLock = new FileLockSub(syncChannel, posAndSize[i][0], + posAndSize[i][1], true); + } catch (IllegalArgumentException iae) { + exceptionThrown = true; + } catch (Exception e) { + System.err.println("Unexpected exception \"" + e + "\" caught" + + " for position " + posAndSize[i][0] + " and size " + + posAndSize[i][1] + " for FileChannel variant"); + failures++; + continue; + } + if (preconditionsHold && exceptionThrown) { + System.err.println("FileLock constructor incorrectly threw IAE" + + " for position " + posAndSize[i][0] + " and size " + + posAndSize[i][1] + " for FileChannel variant"); + failures++; + } else if (!preconditionsHold && !exceptionThrown) { + System.err.println("FileLock constructor did not throw IAE" + + " for position " + posAndSize[i][0] + " and size " + + posAndSize[i][1] + " for FileChannel variant"); + failures++; + } + } + } + + // test position and size preconditions for AsynchronousFileChannel case + try (AsynchronousFileChannel asyncChannel + = AsynchronousFileChannel.open(tmpFile.toPath(), + StandardOpenOption.READ, StandardOpenOption.WRITE)) { + for (int i = 0; i < posAndSize.length; i++) { + boolean preconditionsHold = i == 0; + exceptionThrown = false; + try { + fileLock = new FileLockSub(asyncChannel, posAndSize[i][0], + posAndSize[i][1], true); + } catch (IllegalArgumentException iae) { + exceptionThrown = true; + } catch (Exception e) { + System.err.println("Unexpected exception \"" + e + "\" caught" + + " for position " + posAndSize[i][0] + " and size " + + posAndSize[i][1] + " for AsynchronousFileChannel variant"); + failures++; + continue; + } + if (preconditionsHold && exceptionThrown) { + System.err.println("FileLock constructor incorrectly threw IAE" + + " for position " + posAndSize[i][0] + " and size " + + posAndSize[i][1] + " for AsynchronousFileChannel variant"); + failures++; + } else if (!preconditionsHold && !exceptionThrown) { + System.err.println("FileLock constructor did not throw IAE" + + " for position " + posAndSize[i][0] + " and size " + + posAndSize[i][1] + " for AsynchronousFileChannel variant"); + failures++; + } + } + } + + if (failures > 0) { + throw new RuntimeException("Incurred " + failures + + " failures while testing FileLock."); + } + } +} + +class FileLockSub extends FileLock { + FileLockSub(FileChannel channel, long position, long size, boolean shared) { + super(channel, position, size, shared); + } + + FileLockSub(AsynchronousFileChannel channel, long position, long size, + boolean shared) { + super(channel, position, size, shared); + } + + @Override + public boolean isValid() { + return false; + } + + @Override + public void release() throws IOException { + // do nothing + } +} From 0854df7b86f3ab2b5fa3c3550c857c90a4bfd96c Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Fri, 30 Jan 2015 16:13:04 -0500 Subject: [PATCH 71/72] 8055330: (process spec) ProcessBuilder.start and Runtime.exec should throw UnsupportedOperationException on platforms that don't support Clarify optional behavior and the exception thrown when not supported Reviewed-by: dfuchs, martin --- .../java.base/share/classes/java/lang/ProcessBuilder.java | 6 ++++++ jdk/src/java.base/share/classes/java/lang/Runtime.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java b/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java index 8d4576bd40c..a62594383fc 100644 --- a/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java +++ b/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java @@ -951,6 +951,9 @@ public final class ProcessBuilder * {@code command} array as its argument. This may result in * a {@link SecurityException} being thrown. * + *

    If the operating system does not support the creation of + * processes, an {@link UnsupportedOperationException} will be thrown. + * *

    Starting an operating system process is highly system-dependent. * Among the many things that can go wrong are: *

      @@ -998,6 +1001,9 @@ public final class ProcessBuilder * *
    * + * @throws UnsupportedOperationException + * If the operating system does not support the creation of processes. + * * @throws IOException if an I/O error occurs * * @see Runtime#exec(String[], String[], java.io.File) diff --git a/jdk/src/java.base/share/classes/java/lang/Runtime.java b/jdk/src/java.base/share/classes/java/lang/Runtime.java index 66c78537d39..98bfe2887b5 100644 --- a/jdk/src/java.base/share/classes/java/lang/Runtime.java +++ b/jdk/src/java.base/share/classes/java/lang/Runtime.java @@ -564,6 +564,9 @@ public class Runtime { * cmdarray as its argument. This may result in a * {@link SecurityException} being thrown. * + *

    If the operating system does not support the creation of + * processes, an {@link UnsupportedOperationException} will be thrown. + * *

    Starting an operating system process is highly system-dependent. * Among the many things that can go wrong are: *

      @@ -597,6 +600,9 @@ public class Runtime { * {@link SecurityManager#checkExec checkExec} * method doesn't allow creation of the subprocess * + * @throws UnsupportedOperationException + * If the operating system does not support the creation of processes. + * * @throws IOException * If an I/O error occurs * From 24a3c49404fdc8477a082abb9556d97ec8973b45 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Fri, 30 Jan 2015 16:13:57 -0500 Subject: [PATCH 72/72] 8068284: Missing @throws in DateTimeFormatterBuilder.appendOffset 8068285: Missing @throws in DateTimeFormatterBuilder.appendInstant 8062803: 'principal' should be 'principle' in java.time package description 8062796: java.time.format.DateTimeFormatter error in API doc example Reviewed-by: lancea, mchung --- .../share/classes/java/time/format/DateTimeFormatter.java | 6 ++++-- .../classes/java/time/format/DateTimeFormatterBuilder.java | 2 ++ jdk/src/java.base/share/classes/java/time/package-info.java | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index 02994ad5042..4a5a53cd83c 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -117,8 +117,9 @@ import java.util.Set; * {@code parse(CharSequence text, DateTimeFormatter formatter)}. *

      For example: *

      + *  LocalDate date = LocalDate.now();
        *  String text = date.format(formatter);
      - *  LocalDate date = LocalDate.parse(text, formatter);
      + *  LocalDate parsedDate = LocalDate.parse(text, formatter);
        * 
      *

      * In addition to the format, formatters can be created with desired Locale, @@ -265,9 +266,10 @@ import java.util.Set; *

      * For example: *

      + *  LocalDate date = LocalDate.now();
        *  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
        *  String text = date.format(formatter);
      - *  LocalDate date = LocalDate.parse(text, formatter);
      + *  LocalDate parsedDate = LocalDate.parse(text, formatter);
        * 
      *

      * All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters. The diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 4616017c8e1..a8f70915012 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -849,6 +849,7 @@ public final class DateTimeFormatterBuilder { * @param fractionalDigits the number of fractional second digits to format with, * from 0 to 9, or -1 to use as many digits as necessary * @return this, for chaining, not null + * @throws IllegalArgumentException if the number of fractional digits is invalid */ public DateTimeFormatterBuilder appendInstant(int fractionalDigits) { if (fractionalDigits < -1 || fractionalDigits > 9) { @@ -909,6 +910,7 @@ public final class DateTimeFormatterBuilder { * @param pattern the pattern to use, not null * @param noOffsetText the text to use when the offset is zero, not null * @return this, for chaining, not null + * @throws IllegalArgumentException if the pattern is invalid */ public DateTimeFormatterBuilder appendOffset(String pattern, String noOffsetText) { appendInternal(new OffsetIdPrinterParser(pattern, noOffsetText)); diff --git a/jdk/src/java.base/share/classes/java/time/package-info.java b/jdk/src/java.base/share/classes/java/time/package-info.java index b97a56b9c36..cea222126f1 100644 --- a/jdk/src/java.base/share/classes/java/time/package-info.java +++ b/jdk/src/java.base/share/classes/java/time/package-info.java @@ -65,7 +65,7 @@ * The main API for dates, times, instants, and durations. *

      *

      - * The classes defined here represent the principal date-time concepts, + * The classes defined here represent the principle date-time concepts, * including instants, durations, dates, times, time-zones and periods. * They are based on the ISO calendar system, which is the de facto world * calendar following the proleptic Gregorian rules. @@ -247,8 +247,8 @@ *

    *

    * Multiple calendar systems is an awkward addition to the design challenges. - * The first principal is that most users want the standard ISO calendar system. - * As such, the main classes are ISO-only. The second principal is that most of those that want a + * The first principle is that most users want the standard ISO calendar system. + * As such, the main classes are ISO-only. The second principle is that most of those that want a * non-ISO calendar system want it for user interaction, thus it is a UI localization issue. * As such, date and time objects should be held as ISO objects in the data model and persistent * storage, only being converted to and from a local calendar for display.

  • * If the expression contains a variable reference, its value will be found through the {@link XPathVariableResolver}. * An {@link XPathExpressionException} is raised if the variable resolver is undefined or - * the resolver returns null for the variable. + * the resolver returns {@code null} for the variable. * The value of a variable must be immutable through the course of any single evaluation.

    *
    * If the expression contains a function reference, the function will be found through the {@link XPathFunctionResolver}. * An {@link XPathExpressionException} is raised if the function resolver is undefined or - * the function resolver returns null for the function.

    + * the function resolver returns {@code null} for the function.

    *