diff --git a/8080289-8040213-8189067-move-the-store-out-of-the-loop.patch b/8080289-8040213-8189067-move-the-store-out-of-the-loop.patch new file mode 100644 index 0000000000000000000000000000000000000000..7697d4ec50397d6fa319702c96fcde79e966f65d --- /dev/null +++ b/8080289-8040213-8189067-move-the-store-out-of-the-loop.patch @@ -0,0 +1,687 @@ +From c2d7c271a60a6892bbbf7a2d585aa5b50c85bef1 Mon Sep 17 00:00:00 2001 +From: sunjianye +Date: Sat, 23 May 2020 17:40:00 +0800 +Subject: [PATCH] 8080289 8040213 8189067: move the store out of the loop + +DTS/AR: AR.SR.IREQ02373832.002.001 +Summary: : move the store out of the loop +LLT: NA +Patch Type: backport +Bug url: https://bugs.openjdk.java.net/browse/JDK-8080289 https://bugs.openjdk.java.net/browse/JDK-8040213 https://bugs.openjdk.java.net/browse/JDK-8189067 +--- + hotspot/src/share/vm/opto/loopnode.cpp | 2 +- + hotspot/src/share/vm/opto/loopnode.hpp | 4 +- + hotspot/src/share/vm/opto/loopopts.cpp | 191 +++++++++++ + hotspot/src/share/vm/opto/memnode.cpp | 58 ++-- + hotspot/src/share/vm/opto/phaseX.hpp | 9 +- + .../loopopts/TestMoveStoresOutOfLoops.java | 310 ++++++++++++++++++ + 6 files changed, 545 insertions(+), 29 deletions(-) + create mode 100644 hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoops.java + +diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp +index 0a44d7ede..7ab9bf893 100644 +--- a/hotspot/src/share/vm/opto/loopnode.cpp ++++ b/hotspot/src/share/vm/opto/loopnode.cpp +@@ -1192,7 +1192,7 @@ void CountedLoopEndNode::dump_spec(outputStream *st) const { + //============================================================================= + //------------------------------is_member-------------------------------------- + // Is 'l' a member of 'this'? +-int IdealLoopTree::is_member( const IdealLoopTree *l ) const { ++bool IdealLoopTree::is_member(const IdealLoopTree *l) const { + while( l->_nest > _nest ) l = l->_parent; + return l == this; + } +diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp +index 558b10504..21995dda6 100644 +--- a/hotspot/src/share/vm/opto/loopnode.hpp ++++ b/hotspot/src/share/vm/opto/loopnode.hpp +@@ -371,7 +371,7 @@ public: + { } + + // Is 'l' a member of 'this'? +- int is_member( const IdealLoopTree *l ) const; // Test for nested membership ++ bool is_member(const IdealLoopTree *l) const; // Test for nested membership + + // Set loop nesting depth. Accumulate has_call bits. + int set_nest( uint depth ); +@@ -1075,6 +1075,8 @@ private: + bool split_up( Node *n, Node *blk1, Node *blk2 ); + void sink_use( Node *use, Node *post_loop ); + Node *place_near_use( Node *useblock ) const; ++ Node* try_move_store_before_loop(Node* n, Node *n_ctrl); ++ void try_move_store_after_loop(Node* n); + + bool _created_loop_node; + public: +diff --git a/hotspot/src/share/vm/opto/loopopts.cpp b/hotspot/src/share/vm/opto/loopopts.cpp +index 62273d86d..ec244e363 100644 +--- a/hotspot/src/share/vm/opto/loopopts.cpp ++++ b/hotspot/src/share/vm/opto/loopopts.cpp +@@ -673,6 +673,190 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) { + return iff->in(1); + } + ++#ifdef ASSERT ++static void enqueue_cfg_uses(Node* m, Unique_Node_List& wq) { ++ for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) { ++ Node* u = m->fast_out(i); ++ if (u->is_CFG()) { ++ if (u->Opcode() == Op_NeverBranch) { ++ u = ((NeverBranchNode*)u)->proj_out(0); ++ enqueue_cfg_uses(u, wq); ++ } else { ++ wq.push(u); ++ } ++ } ++ } ++} ++#endif ++ ++// Try moving a store out of a loop, right before the loop ++Node* PhaseIdealLoop::try_move_store_before_loop(Node* n, Node *n_ctrl) { ++ // Store has to be first in the loop body ++ IdealLoopTree *n_loop = get_loop(n_ctrl); ++ if (n->is_Store() && n_loop != _ltree_root && n_loop->is_loop()) { ++ assert(n->in(0), "store should have control set"); ++ Node* address = n->in(MemNode::Address); ++ Node* value = n->in(MemNode::ValueIn); ++ Node* mem = n->in(MemNode::Memory); ++ IdealLoopTree* address_loop = get_loop(get_ctrl(address)); ++ IdealLoopTree* value_loop = get_loop(get_ctrl(value)); ++ ++ // - address and value must be loop invariant ++ // - memory must be a memory Phi for the loop ++ // - Store must be the only store on this memory slice in the ++ // loop: if there's another store following this one then value ++ // written at iteration i by the second store could be overwritten ++ // at iteration i+n by the first store: it's not safe to move the ++ // first store out of the loop ++ // - nothing must observe the Phi memory: it guarantees no read ++ // before the store and no early exit out of the loop ++ // With those conditions, we are also guaranteed the store post ++ // dominates the loop head. Otherwise there would be extra Phi ++ // involved between the loop's Phi and the store. ++ ++ if (!n_loop->is_member(address_loop) && ++ !n_loop->is_member(value_loop) && ++ mem->is_Phi() && mem->in(0) == n_loop->_head && ++ mem->outcnt() == 1 && ++ mem->in(LoopNode::LoopBackControl) == n) { ++ ++#ifdef ASSERT ++ // Verify that store's control does post dominate loop entry and ++ // that there's no early exit of the loop before the store. ++ bool ctrl_ok = false; ++ { ++ // Follow control from loop head until n, we exit the loop or ++ // we reach the tail ++ ResourceMark rm; ++ Unique_Node_List wq; ++ wq.push(n_loop->_head); ++ assert(n_loop->_tail != NULL, "need a tail"); ++ for (uint next = 0; next < wq.size(); ++next) { ++ Node *m = wq.at(next); ++ if (m == n->in(0)) { ++ ctrl_ok = true; ++ continue; ++ } ++ assert(!has_ctrl(m), "should be CFG"); ++ if (!n_loop->is_member(get_loop(m)) || m == n_loop->_tail) { ++ ctrl_ok = false; ++ break; ++ } ++ enqueue_cfg_uses(m, wq); ++ } ++ } ++ assert(ctrl_ok, "bad control"); ++#endif ++ ++ // move the Store ++ _igvn.replace_input_of(mem, LoopNode::LoopBackControl, mem); ++ _igvn.replace_input_of(n, 0, n_loop->_head->in(LoopNode::EntryControl)); ++ _igvn.replace_input_of(n, MemNode::Memory, mem->in(LoopNode::EntryControl)); ++ // Disconnect the phi now. An empty phi can confuse other ++ // optimizations in this pass of loop opts. ++ _igvn.replace_node(mem, mem->in(LoopNode::EntryControl)); ++ n_loop->_body.yank(mem); ++ ++ IdealLoopTree* new_loop = get_loop(n->in(0)); ++ set_ctrl_and_loop(n, n->in(0)); ++ ++ return n; ++ } ++ } ++ return NULL; ++} ++ ++// Try moving a store out of a loop, right after the loop ++void PhaseIdealLoop::try_move_store_after_loop(Node* n) { ++ if (n->is_Store()) { ++ assert(n->in(0), "store should have control set"); ++ Node *n_ctrl = get_ctrl(n); ++ IdealLoopTree *n_loop = get_loop(n_ctrl); ++ // Store must be in a loop ++ if (n_loop != _ltree_root && !n_loop->_irreducible) { ++ Node* address = n->in(MemNode::Address); ++ Node* value = n->in(MemNode::ValueIn); ++ IdealLoopTree* address_loop = get_loop(get_ctrl(address)); ++ // address must be loop invariant ++ if (!n_loop->is_member(address_loop)) { ++ // Store must be last on this memory slice in the loop and ++ // nothing in the loop must observe it ++ Node* phi = NULL; ++ for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { ++ Node* u = n->fast_out(i); ++ if (has_ctrl(u)) { // control use? ++ IdealLoopTree *u_loop = get_loop(get_ctrl(u)); ++ if (!n_loop->is_member(u_loop)) { ++ continue; ++ } ++ if (u->is_Phi() && u->in(0) == n_loop->_head) { ++ assert(_igvn.type(u) == Type::MEMORY, "bad phi"); ++ assert(phi == NULL, "already found"); ++ phi = u; ++ continue; ++ } ++ } ++ phi = NULL; ++ break; ++ } ++ if (phi != NULL) { ++ // Nothing in the loop before the store (next iteration) ++ // must observe the stored value ++ bool mem_ok = true; ++ { ++ ResourceMark rm; ++ Unique_Node_List wq; ++ wq.push(phi); ++ for (uint next = 0; next < wq.size() && mem_ok; ++next) { ++ Node *m = wq.at(next); ++ for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax && mem_ok; i++) { ++ Node* u = m->fast_out(i); ++ if (u->is_Store() || u->is_Phi()) { ++ if (u != n) { ++ wq.push(u); ++ mem_ok = (wq.size() <= 10); ++ } ++ } else { ++ mem_ok = false; ++ break; ++ } ++ } ++ } ++ } ++ if (mem_ok) { ++ // Move the store out of the loop if the LCA of all ++ // users (except for the phi) is outside the loop. ++ Node* hook = new (C) Node(1); ++ _igvn.rehash_node_delayed(phi); ++ int count = phi->replace_edge(n, hook); ++ assert(count > 0, "inconsistent phi"); ++ ++ // Compute latest point this store can go ++ Node* lca = get_late_ctrl(n, get_ctrl(n)); ++ if (n_loop->is_member(get_loop(lca))) { ++ // LCA is in the loop - bail out ++ _igvn.replace_node(hook, n); ++ return; ++ } ++ ++ // Move store out of the loop ++ _igvn.replace_node(hook, n->in(MemNode::Memory)); ++ _igvn.replace_input_of(n, 0, lca); ++ set_ctrl_and_loop(n, lca); ++ ++ // Disconnect the phi now. An empty phi can confuse other ++ // optimizations in this pass of loop opts.. ++ if (phi->in(LoopNode::LoopBackControl) == phi) { ++ _igvn.replace_node(phi, phi->in(LoopNode::EntryControl)); ++ n_loop->_body.yank(phi); ++ } ++ } ++ } ++ } ++ } ++ } ++} ++ + //------------------------------split_if_with_blocks_pre----------------------- + // Do the real work in a non-recursive function. Data nodes want to be + // cloned in the pre-order so they can feed each other nicely. +@@ -703,6 +887,11 @@ Node *PhaseIdealLoop::split_if_with_blocks_pre( Node *n ) { + Node *n_ctrl = get_ctrl(n); + if( !n_ctrl ) return n; // Dead node + ++ Node* res = try_move_store_before_loop(n, n_ctrl); ++ if (res != NULL) { ++ return n; ++ } ++ + // Attempt to remix address expressions for loop invariants + Node *m = remix_address_expressions( n ); + if( m ) return m; +@@ -1057,6 +1246,8 @@ void PhaseIdealLoop::split_if_with_blocks_post( Node *n ) { + } + } + ++ try_move_store_after_loop(n); ++ + // Check for Opaque2's who's loop has disappeared - who's input is in the + // same loop nest as their output. Remove 'em, they are no longer useful. + if( n_op == Op_Opaque2 && +diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp +index 3ecbe1ce0..1bab75927 100644 +--- a/hotspot/src/share/vm/opto/memnode.cpp ++++ b/hotspot/src/share/vm/opto/memnode.cpp +@@ -2313,33 +2313,39 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { + // unsafe if I have intervening uses... Also disallowed for StoreCM + // since they must follow each StoreP operation. Redundant StoreCMs + // are eliminated just before matching in final_graph_reshape. +- if (mem->is_Store() && mem->in(MemNode::Address)->eqv_uncast(address) && +- mem->Opcode() != Op_StoreCM) { +- // Looking at a dead closed cycle of memory? +- assert(mem != mem->in(MemNode::Memory), "dead loop in StoreNode::Ideal"); +- +- assert(Opcode() == mem->Opcode() || +- phase->C->get_alias_index(adr_type()) == Compile::AliasIdxRaw || +- (is_mismatched_access() || mem->as_Store()->is_mismatched_access()), +- "no mismatched stores, except on raw memory"); +- +- if (mem->outcnt() == 1 && // check for intervening uses +- mem->as_Store()->memory_size() <= this->memory_size()) { +- // If anybody other than 'this' uses 'mem', we cannot fold 'mem' away. +- // For example, 'mem' might be the final state at a conditional return. +- // Or, 'mem' might be used by some node which is live at the same time +- // 'this' is live, which might be unschedulable. So, require exactly +- // ONE user, the 'this' store, until such time as we clone 'mem' for +- // each of 'mem's uses (thus making the exactly-1-user-rule hold true). +- if (can_reshape) { // (%%% is this an anachronism?) +- set_req_X(MemNode::Memory, mem->in(MemNode::Memory), +- phase->is_IterGVN()); +- } else { +- // It's OK to do this in the parser, since DU info is always accurate, +- // and the parser always refers to nodes via SafePointNode maps. +- set_req(MemNode::Memory, mem->in(MemNode::Memory)); ++ { ++ Node* st = mem; ++ // If Store 'st' has more than one use, we cannot fold 'st' away. ++ // For example, 'st' might be the final state at a conditional ++ // return. Or, 'st' might be used by some node which is live at ++ // the same time 'st' is live, which might be unschedulable. So, ++ // require exactly ONE user until such time as we clone 'mem' for ++ // each of 'mem's uses (thus making the exactly-1-user-rule hold ++ // true). ++ while (st->is_Store() && st->outcnt() == 1 && st->Opcode() != Op_StoreCM) { ++ // Looking at a dead closed cycle of memory? ++ assert(st != st->in(MemNode::Memory), "dead loop in StoreNode::Ideal"); ++ assert(Opcode() == st->Opcode() || ++ st->Opcode() == Op_StoreVector || ++ Opcode() == Op_StoreVector || ++ phase->C->get_alias_index(adr_type()) == Compile::AliasIdxRaw || ++ (Opcode() == Op_StoreL && st->Opcode() == Op_StoreI), // expanded ClearArrayNode ++ err_msg_res("no mismatched stores, except on raw memory: %s %s", NodeClassNames[Opcode()], NodeClassNames[st->Opcode()])); ++ ++ if (st->in(MemNode::Address)->eqv_uncast(address) && ++ st->as_Store()->memory_size() <= this->memory_size()) { ++ Node* use = st->raw_out(0); ++ phase->igvn_rehash_node_delayed(use); ++ if (can_reshape) { ++ use->set_req_X(MemNode::Memory, st->in(MemNode::Memory), phase->is_IterGVN()); ++ } else { ++ // It's OK to do this in the parser, since DU info is always accurate, ++ // and the parser always refers to nodes via SafePointNode maps. ++ use->set_req(MemNode::Memory, st->in(MemNode::Memory)); ++ } ++ return this; + } +- return this; ++ st = st->in(MemNode::Memory); + } + } + +diff --git a/hotspot/src/share/vm/opto/phaseX.hpp b/hotspot/src/share/vm/opto/phaseX.hpp +index 332b1175d..852a1c295 100644 +--- a/hotspot/src/share/vm/opto/phaseX.hpp ++++ b/hotspot/src/share/vm/opto/phaseX.hpp +@@ -327,6 +327,9 @@ public: + const Type* limit_type) const + { ShouldNotCallThis(); return NULL; } + ++ // Delayed node rehash if this is an IGVN phase ++ virtual void igvn_rehash_node_delayed(Node* n) {} ++ + virtual PhaseIterGVN *is_IterGVN() { return 0; } + + #ifndef PRODUCT +@@ -495,7 +498,11 @@ public: + _worklist.push(n); + } + +- // Replace ith edge of "n" with "in" ++ void igvn_rehash_node_delayed(Node* n) { ++ rehash_node_delayed(n); ++ } ++ ++ // Replace ith edge of "n" with "in" + void replace_input_of(Node* n, int i, Node* in) { + rehash_node_delayed(n); + n->set_req(i, in); +diff --git a/hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoops.java b/hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoops.java +new file mode 100644 +index 000000000..4eea5d5e4 +--- /dev/null ++++ b/hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoops.java +@@ -0,0 +1,310 @@ ++/* ++ * 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 8080289 ++ * @summary Sink stores out of loops if possible ++ * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+PrintCompilation -XX:CompileCommand=dontinline,TestMoveStoresOutOfLoops::test* TestMoveStoresOutOfLoops ++ * ++ */ ++ ++import java.lang.reflect.*; ++import java.util.*; ++import java.util.function.*; ++ ++public class TestMoveStoresOutOfLoops { ++ ++ private static long[] array = new long[10]; ++ private static long[] array2 = new long[10]; ++ private static boolean[] array3 = new boolean[1000]; ++ private static byte[] byte_array = new byte[10]; ++ ++ // Array store should be moved out of the loop, value stored ++ // should be 999, the loop should be eliminated ++ static void test_after_1(int idx) { ++ for (int i = 0; i < 1000; i++) { ++ array[idx] = i; ++ } ++ } ++ ++ // Array store can't be moved out of loop because of following ++ // non loop invariant array access ++ static void test_after_2(int idx) { ++ for (int i = 0; i < 1000; i++) { ++ array[idx] = i; ++ array2[i%10] = i; ++ } ++ } ++ ++ // Array store can't be moved out of loop because of following ++ // use ++ static void test_after_3(int idx) { ++ for (int i = 0; i < 1000; i++) { ++ array[idx] = i; ++ if (array[0] == -1) { ++ break; ++ } ++ } ++ } ++ ++ // Array store can't be moved out of loop because of preceding ++ // use ++ static void test_after_4(int idx) { ++ for (int i = 0; i < 1000; i++) { ++ if (array[0] == -2) { ++ break; ++ } ++ array[idx] = i; ++ } ++ } ++ ++ // All array stores should be moved out of the loop, one after ++ // the other ++ static void test_after_5(int idx) { ++ for (int i = 0; i < 1000; i++) { ++ array[idx] = i; ++ array[idx+1] = i; ++ array[idx+2] = i; ++ array[idx+3] = i; ++ array[idx+4] = i; ++ array[idx+5] = i; ++ } ++ } ++ ++ // Array store can be moved after the loop but needs to be ++ // cloned on both exit paths ++ static void test_after_6(int idx) { ++ for (int i = 0; i < 1000; i++) { ++ array[idx] = i; ++ if (array3[i]) { ++ return; ++ } ++ } ++ } ++ ++ // Optimize out redundant stores ++ static void test_stores_1(int ignored) { ++ array[0] = 0; ++ array[1] = 1; ++ array[2] = 2; ++ array[0] = 0; ++ array[1] = 1; ++ array[2] = 2; ++ } ++ ++ static void test_stores_2(int idx) { ++ array[idx+0] = 0; ++ array[idx+1] = 1; ++ array[idx+2] = 2; ++ array[idx+0] = 0; ++ array[idx+1] = 1; ++ array[idx+2] = 2; ++ } ++ ++ static void test_stores_3(int idx) { ++ byte_array[idx+0] = 0; ++ byte_array[idx+1] = 1; ++ byte_array[idx+2] = 2; ++ byte_array[idx+0] = 0; ++ byte_array[idx+1] = 1; ++ byte_array[idx+2] = 2; ++ } ++ ++ // Array store can be moved out of the loop before the loop header ++ static void test_before_1(int idx) { ++ for (int i = 0; i < 1000; i++) { ++ array[idx] = 999; ++ } ++ } ++ ++ // Array store can't be moved out of the loop before the loop ++ // header because there's more than one store on this slice ++ static void test_before_2(int idx) { ++ for (int i = 0; i < 1000; i++) { ++ array[idx] = 999; ++ array[i%2] = 0; ++ } ++ } ++ ++ // Array store can't be moved out of the loop before the loop ++ // header because of use before store ++ static int test_before_3(int idx) { ++ int res = 0; ++ for (int i = 0; i < 1000; i++) { ++ res += array[i%10]; ++ array[idx] = 999; ++ } ++ return res; ++ } ++ ++ // Array store can't be moved out of the loop before the loop ++ // header because of possible early exit ++ static void test_before_4(int idx) { ++ for (int i = 0; i < 1000; i++) { ++ if (idx / (i+1) > 0) { ++ return; ++ } ++ array[idx] = 999; ++ } ++ } ++ ++ // Array store can't be moved out of the loop before the loop ++ // header because it doesn't postdominate the loop head ++ static void test_before_5(int idx) { ++ for (int i = 0; i < 1000; i++) { ++ if (i % 2 == 0) { ++ array[idx] = 999; ++ } ++ } ++ } ++ ++ // Array store can be moved out of the loop before the loop header ++ static int test_before_6(int idx) { ++ int res = 0; ++ for (int i = 0; i < 1000; i++) { ++ if (i%2 == 1) { ++ res *= 2; ++ } else { ++ res++; ++ } ++ array[idx] = 999; ++ } ++ return res; ++ } ++ ++ final HashMap tests = new HashMap<>(); ++ { ++ for (Method m : this.getClass().getDeclaredMethods()) { ++ if (m.getName().matches("test_(before|after|stores)_[0-9]+")) { ++ assert(Modifier.isStatic(m.getModifiers())) : m; ++ tests.put(m.getName(), m); ++ } ++ } ++ } ++ ++ boolean success = true; ++ void doTest(String name, Runnable init, Function check) throws Exception { ++ Method m = tests.get(name); ++ for (int i = 0; i < 20000; i++) { ++ init.run(); ++ m.invoke(null, 0); ++ success = success && check.apply(name); ++ if (!success) { ++ break; ++ } ++ } ++ } ++ ++ static void array_init() { ++ array[0] = -1; ++ } ++ ++ static boolean array_check(String name) { ++ boolean success = true; ++ if (array[0] != 999) { ++ success = false; ++ System.out.println(name + " failed: array[0] = " + array[0]); ++ } ++ return success; ++ } ++ ++ static void array_init2() { ++ for (int i = 0; i < 6; i++) { ++ array[i] = -1; ++ } ++ } ++ ++ static boolean array_check2(String name) { ++ boolean success = true; ++ for (int i = 0; i < 6; i++) { ++ if (array[i] != 999) { ++ success = false; ++ System.out.println(name + " failed: array[" + i + "] = " + array[i]); ++ } ++ } ++ return success; ++ } ++ ++ static void array_init3() { ++ for (int i = 0; i < 3; i++) { ++ array[i] = -1; ++ } ++ } ++ ++ static boolean array_check3(String name) { ++ boolean success = true; ++ for (int i = 0; i < 3; i++) { ++ if (array[i] != i) { ++ success = false; ++ System.out.println(name + " failed: array[" + i + "] = " + array[i]); ++ } ++ } ++ return success; ++ } ++ ++ static void array_init4() { ++ for (int i = 0; i < 3; i++) { ++ byte_array[i] = -1; ++ } ++ } ++ ++ static boolean array_check4(String name) { ++ boolean success = true; ++ for (int i = 0; i < 3; i++) { ++ if (byte_array[i] != i) { ++ success = false; ++ System.out.println(name + " failed: byte_array[" + i + "] = " + byte_array[i]); ++ } ++ } ++ return success; ++ } ++ ++ static public void main(String[] args) throws Exception { ++ TestMoveStoresOutOfLoops test = new TestMoveStoresOutOfLoops(); ++ test.doTest("test_after_1", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); ++ test.doTest("test_after_2", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); ++ test.doTest("test_after_3", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); ++ test.doTest("test_after_4", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); ++ test.doTest("test_after_5", TestMoveStoresOutOfLoops::array_init2, TestMoveStoresOutOfLoops::array_check2); ++ test.doTest("test_after_6", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); ++ array3[999] = true; ++ test.doTest("test_after_6", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); ++ ++ test.doTest("test_stores_1", TestMoveStoresOutOfLoops::array_init3, TestMoveStoresOutOfLoops::array_check3); ++ test.doTest("test_stores_2", TestMoveStoresOutOfLoops::array_init3, TestMoveStoresOutOfLoops::array_check3); ++ test.doTest("test_stores_3", TestMoveStoresOutOfLoops::array_init4, TestMoveStoresOutOfLoops::array_check4); ++ ++ test.doTest("test_before_1", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); ++ test.doTest("test_before_2", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); ++ test.doTest("test_before_3", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); ++ test.doTest("test_before_4", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); ++ test.doTest("test_before_5", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); ++ test.doTest("test_before_6", TestMoveStoresOutOfLoops::array_init, TestMoveStoresOutOfLoops::array_check); ++ ++ if (!test.success) { ++ throw new RuntimeException("Some tests failed"); ++ } ++ } ++} +-- +2.19.1 + diff --git a/8144993-Elide-redundant-memory-barrier-after-AllocationNode.patch b/8144993-Elide-redundant-memory-barrier-after-AllocationNode.patch new file mode 100644 index 0000000000000000000000000000000000000000..424fd7b28b27e4edd1e9b76a1dd8eb4c3814222e --- /dev/null +++ b/8144993-Elide-redundant-memory-barrier-after-AllocationNode.patch @@ -0,0 +1,258 @@ +From e938b66397096f88ef40f4fc3522a543f938267d Mon Sep 17 00:00:00 2001 +From: sunjianye +Date: Sat, 23 May 2020 18:10:45 +0800 +Subject: [PATCH] 8144993:Elide redundant memory barrier after AllocationNode + and JDK:8139758 + +DTS/AR: AR.SR.IREQ02373832.002.001 +Summary: : Elide redundant memory barrier after AllocationNode +LLT: NA +Patch Type: backport +Bug url: https://bugs.openjdk.java.net/browse/JDK-8144993 https://bugs.openjdk.java.net/browse/JDK-8139758 +--- + hotspot/src/share/vm/opto/callnode.cpp | 18 ++++ + hotspot/src/share/vm/opto/callnode.hpp | 8 ++ + hotspot/src/share/vm/opto/macro.cpp | 17 ++- + hotspot/src/share/vm/opto/parse1.cpp | 8 ++ + hotspot/src/share/vm/opto/parse3.cpp | 5 +- + .../stable/TestStableMemoryBarrier.java | 102 ++++++++++++++++++ + 6 files changed, 151 insertions(+), 7 deletions(-) + create mode 100644 hotspot/test/compiler/stable/TestStableMemoryBarrier.java + +diff --git a/hotspot/src/share/vm/opto/callnode.cpp b/hotspot/src/share/vm/opto/callnode.cpp +index 418f69f60..4ba29841c 100644 +--- a/hotspot/src/share/vm/opto/callnode.cpp ++++ b/hotspot/src/share/vm/opto/callnode.cpp +@@ -1293,6 +1293,7 @@ AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype, + init_flags(Flag_is_macro); + _is_scalar_replaceable = false; + _is_non_escaping = false; ++ _is_allocation_MemBar_redundant = false; + Node *topnode = C->top(); + + init_req( TypeFunc::Control , ctrl ); +@@ -1307,6 +1308,23 @@ AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype, + C->add_macro_node(this); + } + ++void AllocateNode::compute_MemBar_redundancy(ciMethod* initializer) ++{ ++ assert(initializer != NULL && ++ initializer->is_initializer() && ++ !initializer->is_static(), ++ "unexpected initializer method"); ++ BCEscapeAnalyzer* analyzer = initializer->get_bcea(); ++ if (analyzer == NULL) { ++ return; ++ } ++ ++ // Allocation node is first parameter in its initializer ++ if (analyzer->is_arg_stack(0) || analyzer->is_arg_local(0)) { ++ _is_allocation_MemBar_redundant = true; ++ } ++} ++ + //============================================================================= + Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { + if (remove_dead_region(phase, can_reshape)) return this; +diff --git a/hotspot/src/share/vm/opto/callnode.hpp b/hotspot/src/share/vm/opto/callnode.hpp +index f01bc1ec2..4aa46e492 100644 +--- a/hotspot/src/share/vm/opto/callnode.hpp ++++ b/hotspot/src/share/vm/opto/callnode.hpp +@@ -848,6 +848,8 @@ public: + // Result of Escape Analysis + bool _is_scalar_replaceable; + bool _is_non_escaping; ++ // True when MemBar for new is redundant with MemBar at initialzer exit ++ bool _is_allocation_MemBar_redundant; + + virtual uint size_of() const; // Size is bigger + AllocateNode(Compile* C, const TypeFunc *atype, Node *ctrl, Node *mem, Node *abio, +@@ -915,6 +917,12 @@ public: + return _is_non_escaping || (((init = initialization()) != NULL) && init->does_not_escape()); + } + #endif ++ // If object doesn't escape in <.init> method and there is memory barrier ++ // inserted at exit of its <.init>, memory barrier for new is not necessary. ++ // Inovke this method when MemBar at exit of initializer and post-dominate ++ // allocation node. ++ void compute_MemBar_redundancy(ciMethod* initializer); ++ bool is_allocation_MemBar_redundant() { return _is_allocation_MemBar_redundant; } + }; + + //------------------------------AllocateArray--------------------------------- +diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp +index 3c13f973f..628ee6656 100644 +--- a/hotspot/src/share/vm/opto/macro.cpp ++++ b/hotspot/src/share/vm/opto/macro.cpp +@@ -1402,11 +1402,20 @@ void PhaseMacroExpand::expand_allocate_common( + + // If initialization is performed by an array copy, any required + // MemBarStoreStore was already added. If the object does not +- // escape no need for a MemBarStoreStore. Otherwise we need a +- // MemBarStoreStore so that stores that initialize this object +- // can't be reordered with a subsequent store that makes this +- // object accessible by other threads. ++ // escape no need for a MemBarStoreStore. If the object does not ++ // escape in its initializer and memory barrier (MemBarStoreStore or ++ // stronger) is already added at exit of initializer, also no need ++ // for a MemBarStoreStore. Otherwise we need a MemBarStoreStore ++ // so that stores that initialize this object can't be reordered ++ // with a subsequent store that makes this object accessible by ++ // other threads. ++ // Other threads include java threads and JVM internal threads ++ // (for example concurrent GC threads). Current concurrent GC ++ // implementation: CMS and G1 will not scan newly created object, ++ // so it's safe to skip storestore barrier when allocation does ++ // not escape. + if ( AARCH64_ONLY ( !alloc->does_not_escape_thread() && ++ !alloc->is_allocation_MemBar_redundant() && + (init == NULL || + !init->is_complete_with_arraycopy()) ) + NOT_AARCH64 ( init == NULL || +diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp +index 2d6daa159..da0c6dd68 100644 +--- a/hotspot/src/share/vm/opto/parse1.cpp ++++ b/hotspot/src/share/vm/opto/parse1.cpp +@@ -973,6 +973,14 @@ void Parse::do_exits() { + // exceptional returns, since they cannot publish normally. + // + _exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final()); ++ ++ // If Memory barrier is created for final fields write ++ // and allocation node does not escape the initialize method, ++ // then barrier introduced by allocation node can be removed. ++ if (DoEscapeAnalysis && alloc_with_final()) { ++ AllocateNode *alloc = AllocateNode::Ideal_allocation(alloc_with_final(), &_gvn); ++ alloc->compute_MemBar_redundancy(method()); ++ } + #ifndef PRODUCT + if (PrintOpto && (Verbose || WizardMode)) { + method()->print_name(); +diff --git a/hotspot/src/share/vm/opto/parse3.cpp b/hotspot/src/share/vm/opto/parse3.cpp +index abcfc2a48..0e085275f 100644 +--- a/hotspot/src/share/vm/opto/parse3.cpp ++++ b/hotspot/src/share/vm/opto/parse3.cpp +@@ -359,9 +359,8 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) { + set_wrote_final(true); + // Preserve allocation ptr to create precedent edge to it in membar + // generated on exit from constructor. +- if (C->eliminate_boxing() && +- adr_type->isa_oopptr() && adr_type->is_oopptr()->is_ptr_to_boxed_value() && +- AllocateNode::Ideal_allocation(obj, &_gvn) != NULL) { ++ // Can't bind stable with its allocation, only record allocation for final field. ++ if (field->is_final() && AllocateNode::Ideal_allocation(obj, &_gvn) != NULL) { + set_alloc_with_final(obj); + } + } +diff --git a/hotspot/test/compiler/stable/TestStableMemoryBarrier.java b/hotspot/test/compiler/stable/TestStableMemoryBarrier.java +new file mode 100644 +index 000000000..c9724f54f +--- /dev/null ++++ b/hotspot/test/compiler/stable/TestStableMemoryBarrier.java +@@ -0,0 +1,102 @@ ++/* ++ * 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. ++ */ ++ ++/* ++ * @test TestStableMemoryBarrier ++ * @bug 8139758 ++ * @summary tests memory barrier correctly inserted for stable fields ++ * @library /testlibrary /testlibrary/whitebox ++ * @build TestStableMemoryBarrier StableConfiguration sun.hotspot.WhiteBox ++ * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission ++ * @run main ClassFileInstaller ++ * java/lang/invoke/StableConfiguration ++ * java/lang/invoke/TestStableMemoryBarrier ++ * java/lang/invoke/TestStableMemoryBarrier$NotDominate ++ * ++ * @run main/othervm -Xbootclasspath/a:. ++ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp ++ * -XX:-TieredCompilation ++ * -XX:+FoldStableValues ++ * -XX:CompileOnly=::testCompile ++ * java.lang.invoke.TestStableMemoryBarrier ++ * ++ * @author hui.shi@linaro.org ++ */ ++ ++package java.lang.invoke; ++ ++import java.lang.reflect.InvocationTargetException; ++ ++public class TestStableMemoryBarrier { ++ ++ public static void main(String[] args) throws Exception { ++ run(NotDominate.class); ++ ++ } ++ ++ /* ==================================================== ++ * Stable field initialized in method, but its allocation ++ * doesn't dominate MemBar Release at the end of method. ++ */ ++ ++ static class NotDominate{ ++ public @Stable int v; ++ public static int[] array = new int[100]; ++ public static NotDominate testCompile(int n) { ++ if ((n % 2) == 0) return null; ++ // add a loop here, trigger PhaseIdealLoop::verify_dominance ++ for (int i = 0; i < 100; i++) { ++ array[i] = n; ++ } ++ NotDominate nm = new NotDominate(); ++ nm.v = n; ++ return nm; ++ } ++ ++ public static void test() throws Exception { ++ for (int i = 0; i < 1000000; i++) ++ testCompile(i); ++ } ++ } ++ ++ public static void run(Class test) { ++ Throwable ex = null; ++ System.out.print(test.getName()+": "); ++ try { ++ test.getMethod("test").invoke(null); ++ } catch (InvocationTargetException e) { ++ ex = e.getCause(); ++ } catch (Throwable e) { ++ ex = e; ++ } finally { ++ if (ex == null) { ++ System.out.println("PASSED"); ++ } else { ++ System.out.println("FAILED"); ++ ex.printStackTrace(System.out); ++ } ++ } ++ } ++} +-- +2.19.1 + diff --git a/8182397-race-in-field-updates.patch b/8182397-race-in-field-updates.patch index 196077b2ef5d31723acfabbab456ed6765627a74..abf0620d4d6385af8db791d2864622ef913cb08f 100644 --- a/8182397-race-in-field-updates.patch +++ b/8182397-race-in-field-updates.patch @@ -15,10 +15,10 @@ Bug url: https://bugs.openjdk.java.net/browse/JDK-8182397 create mode 100644 hotspot/test/runtime/CreateMirror/ArraysNewInstanceBug.java diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp -index cd28c758d0..e010c77cd1 100644 +index 86cb361c..4db165d4 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp -@@ -573,6 +573,7 @@ void java_lang_Class::initialize_mirror_fields(KlassHandle k, +@@ -575,6 +575,7 @@ void java_lang_Class::initialize_mirror_fields(KlassHandle k, void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, Handle protection_domain, TRAPS) { @@ -26,7 +26,7 @@ index cd28c758d0..e010c77cd1 100644 assert(k->java_mirror() == NULL, "should only assign mirror once"); // Use this moment of initialization to cache modifier_flags also, // to support Class.getModifiers(). Instance classes recalculate -@@ -585,11 +586,10 @@ void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, +@@ -587,11 +588,10 @@ void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, if (SystemDictionary::Class_klass_loaded()) { // Allocate mirror (java.lang.Class instance) Handle mirror = InstanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance(k, CHECK); @@ -40,7 +40,7 @@ index cd28c758d0..e010c77cd1 100644 InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass()); assert(oop_size(mirror()) == mk->instance_size(k), "should have been set"); -@@ -598,21 +598,21 @@ void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, +@@ -600,21 +600,21 @@ void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, // It might also have a component mirror. This mirror must already exist. if (k->oop_is_array()) { @@ -67,8 +67,8 @@ index cd28c758d0..e010c77cd1 100644 } else { assert(k->oop_is_instance(), "Must be"); -@@ -631,10 +631,13 @@ void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, - assert(oopDesc::equals(class_loader(), k->class_loader()), "should be same"); +@@ -633,10 +633,13 @@ void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, + assert(class_loader() == k->class_loader(), "should be same"); set_class_loader(mirror(), class_loader()); - // Setup indirection from klass->mirror last @@ -84,7 +84,7 @@ index cd28c758d0..e010c77cd1 100644 } } else { if (fixup_mirror_list() == NULL) { -@@ -715,7 +718,7 @@ oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, Basic +@@ -716,7 +719,7 @@ oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, Basic if (type != T_VOID) { Klass* aklass = Universe::typeArrayKlassObj(type); assert(aklass != NULL, "correct bootstrap"); @@ -93,7 +93,7 @@ index cd28c758d0..e010c77cd1 100644 } #ifdef ASSERT InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(SystemDictionary::Class_klass()); -@@ -812,9 +815,9 @@ Klass* java_lang_Class::array_klass(oop java_class) { +@@ -813,9 +816,9 @@ Klass* java_lang_Class::array_klass(oop java_class) { } @@ -106,7 +106,7 @@ index cd28c758d0..e010c77cd1 100644 diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp -index 51879658c7..d9e65f9014 100644 +index 51879658..d9e65f90 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -281,7 +281,7 @@ class java_lang_Class : AllStatic { @@ -119,10 +119,10 @@ index 51879658c7..d9e65f9014 100644 static int klass_offset_in_bytes() { return _klass_offset; } static int array_klass_offset_in_bytes() { return _array_klass_offset; } diff --git a/hotspot/src/share/vm/oops/oop.hpp b/hotspot/src/share/vm/oops/oop.hpp -index c8d1f99183..c9bcf96d1c 100644 +index 5e598b4b..a703a54e 100644 --- a/hotspot/src/share/vm/oops/oop.hpp +++ b/hotspot/src/share/vm/oops/oop.hpp -@@ -243,6 +243,8 @@ class oopDesc { +@@ -203,6 +203,8 @@ class oopDesc { Metadata* metadata_field(int offset) const; void metadata_field_put(int offset, Metadata* value); @@ -132,11 +132,11 @@ index c8d1f99183..c9bcf96d1c 100644 void byte_field_put(int offset, jbyte contents); diff --git a/hotspot/src/share/vm/oops/oop.inline.hpp b/hotspot/src/share/vm/oops/oop.inline.hpp -index 5d47e3f4dc..16d2870d79 100644 +index a76b8506..d4c4d75c 100644 --- a/hotspot/src/share/vm/oops/oop.inline.hpp +++ b/hotspot/src/share/vm/oops/oop.inline.hpp -@@ -393,6 +393,10 @@ inline void oopDesc::metadata_field_put(int offset, Metadata* value) { - } +@@ -373,6 +373,10 @@ inline void oopDesc::metadata_field_put(int offset, Metadata* value) { + *metadata_field_addr(offset) = value; } +void oopDesc::release_metadata_field_put(int offset, Metadata* value) { @@ -144,11 +144,11 @@ index 5d47e3f4dc..16d2870d79 100644 +} + inline void oopDesc::obj_field_put_raw(int offset, oop value) { - if (UseShenandoahGC) { - oop p = bs()->write_barrier(this); + UseCompressedOops ? + encode_store_heap_oop(obj_field_addr(offset), value) : diff --git a/hotspot/test/runtime/CreateMirror/ArraysNewInstanceBug.java b/hotspot/test/runtime/CreateMirror/ArraysNewInstanceBug.java new file mode 100644 -index 0000000000..870e8ea94b +index 00000000..870e8ea9 --- /dev/null +++ b/hotspot/test/runtime/CreateMirror/ArraysNewInstanceBug.java @@ -0,0 +1,83 @@ diff --git a/8223504-improve-performance-of-forall-loops-by-better.patch b/8223504-improve-performance-of-forall-loops-by-better.patch new file mode 100644 index 0000000000000000000000000000000000000000..c142025c74f398dd5f278dfff0f9c2c84a925f94 --- /dev/null +++ b/8223504-improve-performance-of-forall-loops-by-better.patch @@ -0,0 +1,79 @@ +From c1d5b7c044ba418848c98d36ec21358a1dac568e Mon Sep 17 00:00:00 2001 +From: sunjianye +Date: Sat, 23 May 2020 17:18:39 +0800 +Subject: [PATCH] 8223504:improve performance of forall loops by better + inlining of "iterator()" methods + +DTS/AR: AR.SR.IREQ02373832.002.001 +Summary: : improve performance of forall loops by better inlining of "iterator()" methods +LLT: NA +Patch Type: backport +Bug url: https://bugs.openjdk.java.net/browse/JDK-8223504 +--- + hotspot/src/share/vm/classfile/systemDictionary.hpp | 3 +++ + hotspot/src/share/vm/classfile/vmSymbols.hpp | 2 ++ + hotspot/src/share/vm/opto/bytecodeInfo.cpp | 9 ++++++++- + 3 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp +index 57a9d669b..956b50313 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp ++++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp +@@ -196,6 +196,9 @@ class Ticks; + do_klass(Short_klass, java_lang_Short, Pre ) \ + do_klass(Integer_klass, java_lang_Integer, Pre ) \ + do_klass(Long_klass, java_lang_Long, Pre ) \ ++ \ ++ /* force inline of iterators */ \ ++ do_klass(Iterator_klass, java_util_Iterator, Pre ) \ + /*end*/ + + +diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp +index 46f2e2d8b..acc33fcc2 100644 +--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp ++++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp +@@ -121,6 +121,8 @@ + template(sun_misc_Launcher_AppClassLoader, "sun/misc/Launcher$AppClassLoader") \ + template(sun_misc_Launcher_ExtClassLoader, "sun/misc/Launcher$ExtClassLoader") \ + \ ++ template(java_util_Iterator, "java/util/Iterator") \ ++ \ + /* Java runtime version access */ \ + template(sun_misc_Version, "sun/misc/Version") \ + template(java_runtime_name_name, "java_runtime_name") \ +diff --git a/hotspot/src/share/vm/opto/bytecodeInfo.cpp b/hotspot/src/share/vm/opto/bytecodeInfo.cpp +index d16b5631b..06a30b94a 100644 +--- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp ++++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1998, 2020, 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 +@@ -75,6 +75,8 @@ InlineTree::InlineTree(Compile* c, + * Return true when EA is ON and a java constructor is called or + * a super constructor is called from an inlined java constructor. + * Also return true for boxing methods. ++ * Also return true for methods returning Iterator (including Iterable::iterator()) ++ * that is essential for forall-loops performance. + */ + static bool is_init_with_ea(ciMethod* callee_method, + ciMethod* caller_method, Compile* C) { +@@ -92,6 +94,11 @@ static bool is_init_with_ea(ciMethod* callee_method, + if (C->eliminate_boxing() && callee_method->is_boxing_method()) { + return true; + } ++ ciType *retType = callee_method->signature()->return_type(); ++ ciKlass *iter = C->env()->Iterator_klass(); ++ if (retType->is_loaded() && iter->is_loaded() && retType->is_subtype_of(iter)) { ++ return true; ++ } + return false; + } + +-- +2.19.1 + diff --git a/aarch64-shenandoah-jdk8u262-b05.tar.xz b/aarch64-port-jdk8u-shenandoah-aarch64-shenandoah-jdk8u262-b10.tar.xz similarity index 81% rename from aarch64-shenandoah-jdk8u262-b05.tar.xz rename to aarch64-port-jdk8u-shenandoah-aarch64-shenandoah-jdk8u262-b10.tar.xz index 6c798e86bb71eea39ad1698c599c9483469f42f3..fd2956756e6bf6ecc096aeaaac4ee53ea93e1a72 100644 Binary files a/aarch64-shenandoah-jdk8u262-b05.tar.xz and b/aarch64-port-jdk8u-shenandoah-aarch64-shenandoah-jdk8u262-b10.tar.xz differ diff --git a/add-vm-option-BoxTypeCachedMax-for-Integer-and-Long-cache.patch b/add-vm-option-BoxTypeCachedMax-for-Integer-and-Long-cache.patch new file mode 100644 index 0000000000000000000000000000000000000000..4a879c5bda27c37903bed2af9978d29f7ad7e8a9 --- /dev/null +++ b/add-vm-option-BoxTypeCachedMax-for-Integer-and-Long-cache.patch @@ -0,0 +1,166 @@ +From b5c192bb3dc57021996545b0bac822d73c75ec19 Mon Sep 17 00:00:00 2001 +From: sunjianye +Date: Thu, 23 Apr 2020 16:12:34 +0800 +Subject: [PATCH] add vm option BoxTypeCachedMax for Integer and Long cache + +DTS/AR: AR.SR.IREQ02373832.002.001 +Summary: < JDK> : add vm option BoxTypeCachedMax for Integer and Long cache +LLT: NA +Patch Type: huawei +Bug url: NA +--- + hotspot/src/share/vm/opto/c2_globals.hpp | 3 ++ + hotspot/src/share/vm/runtime/arguments.cpp | 23 ++++++++++++ + hotspot/src/share/vm/runtime/arguments.hpp | 3 ++ + jdk/src/share/classes/java/lang/Long.java | 43 ++++++++++++++++++---- + 4 files changed, 65 insertions(+), 7 deletions(-) + +diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp +index 4b6a87508..3f2d286b2 100644 +--- a/hotspot/src/share/vm/opto/c2_globals.hpp ++++ b/hotspot/src/share/vm/opto/c2_globals.hpp +@@ -470,6 +470,9 @@ + product(intx, AutoBoxCacheMax, 128, \ + "Sets max value cached by the java.lang.Integer autobox cache") \ + \ ++ product(intx, BoxTypeCachedMax, 128, \ ++ "Sets max value cached by the java.lang.Long and Integer autobox cache") \ ++ \ + experimental(bool, AggressiveUnboxing, false, \ + "Control optimizations for aggressive boxing elimination") \ + \ +diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp +index 63b39c4ba..75ef29b9b 100644 +--- a/hotspot/src/share/vm/runtime/arguments.cpp ++++ b/hotspot/src/share/vm/runtime/arguments.cpp +@@ -2194,6 +2194,24 @@ void Arguments::set_bytecode_flags() { + } + } + ++// set Integer and Long box type cached MAX num flag : -XX:BoxTypeCachedMax= ++void Arguments::set_boxtype_cached_max_flags() { ++ int size = 1024; ++ char buffer[size]; ++ jio_snprintf(buffer, size, "java.lang.Long.LongCache.high=" INTX_FORMAT, BoxTypeCachedMax); ++ add_property(buffer); ++ ++ if (AggressiveOpts || !FLAG_IS_DEFAULT(AutoBoxCacheMax)) { ++ if (FLAG_IS_DEFAULT(AutoBoxCacheMax)) { ++ FLAG_SET_DEFAULT(AutoBoxCacheMax, 20000); ++ } ++ jio_snprintf(buffer, size, "java.lang.Integer.IntegerCache.high=" INTX_FORMAT, AutoBoxCacheMax); ++ } else { ++ jio_snprintf(buffer, size, "java.lang.Integer.IntegerCache.high=" INTX_FORMAT, BoxTypeCachedMax); ++ } ++ add_property(buffer); ++} ++ + // Aggressive optimization flags -XX:+AggressiveOpts + void Arguments::set_aggressive_opts_flags() { + #ifdef COMPILER2 +@@ -2846,6 +2864,8 @@ bool Arguments::check_vm_args_consistency() { + // Check the minimum number of compiler threads + status &=verify_min_value(CICompilerCount, min_number_of_compiler_threads, "CICompilerCount"); + ++ status &= verify_min_value(BoxTypeCachedMax, 1, "BoxTypeCachedMax"); ++ + return status; + } + +@@ -4336,6 +4356,9 @@ jint Arguments::apply_ergo() { + // Set bytecode rewriting flags + set_bytecode_flags(); + ++ // Set Integer and Long cached max ++ set_boxtype_cached_max_flags(); ++ + // Set flags if Aggressive optimization flags (-XX:+AggressiveOpts) enabled. + set_aggressive_opts_flags(); + +diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp +index a5cd59ea6..6f7ff138f 100644 +--- a/hotspot/src/share/vm/runtime/arguments.hpp ++++ b/hotspot/src/share/vm/runtime/arguments.hpp +@@ -386,6 +386,9 @@ class Arguments : AllStatic { + // System properties + static bool add_property(const char* prop); + ++ // set Integer and Long box type cached MAX num ++ static void set_boxtype_cached_max_flags(); ++ + // Aggressive optimization flags. + static void set_aggressive_opts_flags(); + +diff --git a/jdk/src/share/classes/java/lang/Long.java b/jdk/src/share/classes/java/lang/Long.java +index 9e21cb853..d56f4c6be 100644 +--- a/jdk/src/share/classes/java/lang/Long.java ++++ b/jdk/src/share/classes/java/lang/Long.java +@@ -804,13 +804,43 @@ public final class Long extends Number implements Comparable { + } + + private static class LongCache { ++ static final int low; ++ static final int high; ++ + private LongCache(){} + +- static final Long cache[] = new Long[-(-128) + 127 + 1]; ++ static final Long cache[]; + + static { +- for(int i = 0; i < cache.length; i++) +- cache[i] = new Long(i - 128); ++ ++ String longCacheHighPropValue = ++ sun.misc.VM.getSavedProperty("java.lang.Long.LongCache.high"); ++ if (longCacheHighPropValue != null) { ++ // high value may be configured by property ++ int h = 0; ++ try { ++ int i = Integer.parseInt(longCacheHighPropValue); ++ i = Math.max(i, 128); ++ // Maximum array size is Integer.MAX_VALUE ++ h = Math.min(i, Integer.MAX_VALUE/2 -1); ++ } catch( NumberFormatException nfe) { ++ // If the property cannot be parsed into an int, ignore it. ++ } ++ high = h; ++ low = -h+1; ++ cache = new Long[(high - low) + 1]; ++ int j = low; ++ for(int k = 0; k < cache.length; k++) ++ cache[k] = new Long(j++); ++ ++ } else { ++ low = -128; ++ high = 127; ++ cache = new Long[(high - low) + 1]; ++ int j = low; ++ for(int k = 0; k < cache.length; k++) ++ cache[k] = new Long(j++); ++ } + } + } + +@@ -833,10 +863,8 @@ public final class Long extends Number implements Comparable { + * @since 1.5 + */ + public static Long valueOf(long l) { +- final int offset = 128; +- if (l >= -128 && l <= 127) { // will cache +- return LongCache.cache[(int)l + offset]; +- } ++ if (l >= LongCache.low && l <= LongCache.high) ++ return LongCache.cache[(int) l + (-LongCache.low)]; + return new Long(l); + } + +@@ -1617,4 +1645,5 @@ public final class Long extends Number implements Comparable { + + /** use serialVersionUID from JDK 1.0.2 for interoperability */ + @Native private static final long serialVersionUID = 4290774380558885855L; ++ + } +-- +2.19.1 + diff --git a/add-with-company-name-option.patch b/add-with-company-name-option.patch index b3c7311188b7e0b276426495a35b3e538c6f8bb6..8be1ece5fe9ab30f298a23b8ff4403a9720641e2 100644 --- a/add-with-company-name-option.patch +++ b/add-with-company-name-option.patch @@ -94,7 +94,7 @@ index df886e88f4..c0c7b7bdb3 100644 +company_name = +ifneq ($(COMPANY_NAME),N/A) -+ company_name=($(COMPANY_NAME)) ++ company_name=$(COMPANY_NAME) +endif + $(JDK_OUTPUTDIR)/gensrc/sun/misc/Version.java \ @@ -127,7 +127,7 @@ index 32e2586e79..022c142810 100644 /* Second line: runtime version (ie, libraries). */ - ps.print(java_runtime_name + " (build " + java_runtime_version); -+ ps.print(java_runtime_name + " " + company_name + "(build " + java_runtime_version); ++ ps.print(java_runtime_name + " " + company_name + " " + "(build " + java_runtime_version); if (java_profile_name.length() > 0) { // profile name @@ -137,7 +137,7 @@ index 32e2586e79..022c142810 100644 String java_vm_info = System.getProperty("java.vm.info"); - ps.println(java_vm_name + " (build " + java_vm_version + ", " + - java_vm_info + ")"); -+ ps.println(java_vm_name + " " + company_name + "(build " + java_vm_version + ", " + ++ ps.println(java_vm_name + " " + company_name + " " + "(build " + java_vm_version + ", " + + java_vm_info + ")"); } diff --git a/fast-serializer-jdk8.patch b/fast-serializer-jdk8.patch new file mode 100644 index 0000000000000000000000000000000000000000..88f6a31ec4919fcc7941281d4be5f681a978b661 --- /dev/null +++ b/fast-serializer-jdk8.patch @@ -0,0 +1,679 @@ +commit 3ece3b6a87e4bf61a1f786c12d796012becce313 +Author: hexuejin +Date: Thu May 28 10:30:20 2020 +0800 + + Add FastSerializer + + DTS/AR: AR.SR.IREQ02369011.001.001 + Summary:: Add FastSerializer + LLT: jtreg + Patch Type: huawei + Bug url: NA + +diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp +index cdb72c0d5..d50041635 100644 +--- a/hotspot/src/share/vm/prims/unsafe.cpp ++++ b/hotspot/src/share/vm/prims/unsafe.cpp +@@ -1361,6 +1361,10 @@ UNSAFE_ENTRY(void, Unsafe_PrefetchWrite(JNIEnv* env, jclass ignored, jobject obj + Prefetch::write(addr, (intx)offset); + UNSAFE_END + ++UNSAFE_ENTRY(jboolean, Unsafe_GetUseFastSerializer(JNIEnv *env, jobject unsafe)) { ++ return UseFastSerializer; ++} ++UNSAFE_END + + /// JVM_RegisterUnsafeMethods + +@@ -1447,7 +1451,8 @@ static JNINativeMethod methods_140[] = { + {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 "throwException", CC "(" THR ")V", FN_PTR(Unsafe_ThrowException)}, ++ {CC "getUseFastSerializer", CC "()Z", FN_PTR(Unsafe_GetUseFastSerializer)} + }; + + // These are the methods prior to the JSR 166 changes in 1.5.0 +@@ -1493,8 +1498,8 @@ static JNINativeMethod methods_141[] = { + {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 "throwException", CC "(" THR ")V", FN_PTR(Unsafe_ThrowException)}, ++ {CC "getUseFastSerializer", CC "()Z", FN_PTR(Unsafe_GetUseFastSerializer)} + }; + + // These are the methods prior to the JSR 166 changes in 1.6.0 +@@ -1548,7 +1553,8 @@ static JNINativeMethod methods_15[] = { + {CC "compareAndSwapInt", CC "(" OBJ "J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, + {CC "compareAndSwapLong", CC "(" OBJ "J""J""J"")Z", FN_PTR(Unsafe_CompareAndSwapLong)}, + {CC "park", CC "(ZJ)V", FN_PTR(Unsafe_Park)}, +- {CC "unpark", CC "(" OBJ ")V", FN_PTR(Unsafe_Unpark)} ++ {CC "unpark", CC "(" OBJ ")V", FN_PTR(Unsafe_Unpark)}, ++ {CC "getUseFastSerializer", CC "()Z", FN_PTR(Unsafe_GetUseFastSerializer)} + + }; + +@@ -1606,7 +1612,8 @@ static JNINativeMethod methods_16[] = { + {CC "putOrderedInt", CC "(" OBJ "JI)V", FN_PTR(Unsafe_SetOrderedInt)}, + {CC "putOrderedLong", CC "(" OBJ "JJ)V", FN_PTR(Unsafe_SetOrderedLong)}, + {CC "park", CC "(ZJ)V", FN_PTR(Unsafe_Park)}, +- {CC "unpark", CC "(" OBJ ")V", FN_PTR(Unsafe_Unpark)} ++ {CC "unpark", CC "(" OBJ ")V", FN_PTR(Unsafe_Unpark)}, ++ {CC "getUseFastSerializer", CC "()Z", FN_PTR(Unsafe_GetUseFastSerializer)} + }; + + // These are the methods for 1.8.0 +@@ -1662,7 +1669,8 @@ static JNINativeMethod methods_18[] = { + {CC "putOrderedInt", CC "(" OBJ "JI)V", FN_PTR(Unsafe_SetOrderedInt)}, + {CC "putOrderedLong", CC "(" OBJ "JJ)V", FN_PTR(Unsafe_SetOrderedLong)}, + {CC "park", CC "(ZJ)V", FN_PTR(Unsafe_Park)}, +- {CC "unpark", CC "(" OBJ ")V", FN_PTR(Unsafe_Unpark)} ++ {CC "unpark", CC "(" OBJ ")V", FN_PTR(Unsafe_Unpark)}, ++ {CC "getUseFastSerializer", CC "()Z", FN_PTR(Unsafe_GetUseFastSerializer)} + }; + + JNINativeMethod loadavg_method[] = { +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index 2e6ff26ed..0a6ebfae1 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -553,6 +553,10 @@ class CommandLineFlags { + "Enable normal processing of flags relating to experimental " \ + "features") \ + \ ++ experimental(bool, UseFastSerializer, false, \ ++ "Cache-based serialization.It is extremely fast, but it can only" \ ++ "be effective in certain scenarios.") \ ++ \ + product(bool, JavaMonitorsInStackTrace, true, \ + "Print information about Java monitor locks when the stacks are" \ + "dumped") \ +diff --git a/jdk/src/share/classes/java/io/ObjectInputStream.java b/jdk/src/share/classes/java/io/ObjectInputStream.java +index 5d30f2a01..b67f01719 100644 +--- a/jdk/src/share/classes/java/io/ObjectInputStream.java ++++ b/jdk/src/share/classes/java/io/ObjectInputStream.java +@@ -49,6 +49,7 @@ import sun.misc.SharedSecrets; + import sun.misc.JavaOISAccess; + import sun.util.logging.PlatformLogger; + import sun.security.action.GetBooleanAction; ++import sun.misc.Unsafe; + + /** + * An ObjectInputStream deserializes primitive data and objects previously +@@ -284,6 +285,22 @@ public class ObjectInputStream + traceLogger = (filterLog != null && + filterLog.isLoggable(PlatformLogger.Level.FINER)) ? filterLog : null; + } ++ ++ /* ++ * Logger for FastSerializer. ++ * Setup the FastSerializer logger if it is set to FINE ++ * (Assuming it will not change). ++ */ ++ private static final PlatformLogger fastSerLogger; ++ static { ++ if (printFastSerializer) { ++ PlatformLogger fastSerLog = PlatformLogger.getLogger("fastSerializer"); ++ fastSerLogger = (fastSerLog != null && ++ fastSerLog.isLoggable(PlatformLogger.Level.FINE)) ? fastSerLog : null; ++ } else { ++ fastSerLogger = null; ++ } ++ } + } + + /** filter stream for handling block data conversion */ +@@ -312,6 +329,9 @@ public class ObjectInputStream + /** if true, invoke resolveObject() */ + private boolean enableResolve; + ++ /** Used to get the commandline option: useFastSerializer */ ++ private static final Unsafe UNSAFE = Unsafe.getUnsafe(); ++ + /** + * Context during upcalls to class-defined readObject methods; holds + * object currently being deserialized and descriptor for current class. +@@ -325,6 +345,33 @@ public class ObjectInputStream + */ + private ObjectInputFilter serialFilter; + ++ /** ++ * value of "useFastSerializer" property ++ */ ++ private static final boolean defaultFastSerializer = UNSAFE.getUseFastSerializer(); ++ ++ /** ++ * true or false for open FastSerilizer ++ * May be changed in readStreamHeader ++ */ ++ private boolean useFastSerializer = defaultFastSerializer; ++ ++ /** ++ * Value of "fastSerializerEscapeMode" property. It can be turned on ++ * when useFastSerializer is true. ++ */ ++ private static final boolean fastSerializerEscapeMode = java.security.AccessController.doPrivileged( ++ new sun.security.action.GetBooleanAction( ++ "fastSerializerEscapeMode")).booleanValue(); ++ ++ /** ++ * value of "printFastSerializer" property, ++ * as true or false for printing FastSerializer logs. ++ */ ++ private static final boolean printFastSerializer = java.security.AccessController.doPrivileged( ++ new sun.security.action.GetBooleanAction( ++ "printFastSerializer")).booleanValue(); ++ + /** + * Creates an ObjectInputStream that reads from the specified InputStream. + * A serialization stream header is read from the stream and verified. +@@ -396,6 +443,9 @@ public class ObjectInputStream + * transitively so that a complete equivalent graph of objects is + * reconstructed by readObject. + * ++ * The difference between fastSerialzation and default serialization is the ++ * descriptor serialization. The data serialization is same with each other. ++ * + *

The root object is completely restored when all of its fields and the + * objects it references are completely restored. At this point the object + * validation callbacks are executed in order based on their registered +@@ -670,11 +720,20 @@ public class ObjectInputStream + vlist.register(obj, prio); + } + ++ /** ++ * Cache the class meta during serialization. ++ * Only used in FastSerilizer. ++ */ ++ protected static ConcurrentHashMap> nameToClass = new ConcurrentHashMap<>(); ++ + /** + * Load the local class equivalent of the specified stream class + * description. Subclasses may implement this method to allow classes to + * be fetched from an alternate source. + * ++ * When fastSerializer is turned on, fields of desc will be null except ++ * name. When resolveClass is override, this may cause null pointer exception. ++ * + *

The corresponding method in ObjectOutputStream is + * annotateClass. This method will be invoked only once for + * each unique class in the stream. This method can be implemented by +@@ -715,16 +774,27 @@ public class ObjectInputStream + throws IOException, ClassNotFoundException + { + String name = desc.getName(); ++ Class cl = null; ++ ++ if (useFastSerializer) { ++ cl = nameToClass.get(name); ++ if (cl != null) { ++ return cl; ++ } ++ } + try { +- return Class.forName(name, false, latestUserDefinedLoader()); ++ cl = Class.forName(name, false, latestUserDefinedLoader()); + } catch (ClassNotFoundException ex) { +- Class cl = primClasses.get(name); +- if (cl != null) { +- return cl; +- } else { ++ cl = primClasses.get(name); ++ if (cl == null) { + throw ex; + } + } ++ if (useFastSerializer) { ++ nameToClass.put(name, cl); ++ } ++ ++ return cl; + } + + /** +@@ -894,9 +964,34 @@ public class ObjectInputStream + { + short s0 = bin.readShort(); + short s1 = bin.readShort(); +- if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) { +- throw new StreamCorruptedException( +- String.format("invalid stream header: %04X%04X", s0, s1)); ++ if (useFastSerializer) { ++ if (s0 != STREAM_MAGIC_FAST || s1 != STREAM_VERSION) { ++ ++ if (s0 != STREAM_MAGIC) { ++ throw new StreamCorruptedException( ++ String.format("invalid stream header: %04X%04X, and FastSerializer is activated", s0, s1)); ++ } ++ ++ if (!fastSerializerEscapeMode) { ++ throw new StreamCorruptedException( ++ String.format("invalid stream header: %04X%04X.Fast serialization does not support " + ++ "original serialized files", s0, s1)); ++ } ++ ++ // Escape to default serialization ++ useFastSerializer = false; ++ if (Logging.fastSerLogger != null) { ++ Logging.fastSerLogger.fine("[Deserialize]: Escape and disable FastSerializer"); ++ } ++ } ++ } else if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) { ++ if (s0 == STREAM_MAGIC_FAST && s1 == STREAM_VERSION) { ++ throw new StreamCorruptedException( ++ String.format("invalid stream header: %04X%04X, and it is a FastSerializer stream", s0, s1)); ++ } else { ++ throw new StreamCorruptedException( ++ String.format("invalid stream header: %04X%04X", s0, s1)); ++ } + } + } + +@@ -910,6 +1005,11 @@ public class ObjectInputStream + * this method reads class descriptors according to the format defined in + * the Object Serialization specification. + * ++ * In fastSerialize mode, the descriptor is obtained by lookup method. And ++ * the resolveClass method is called here to get the classmeta. Since the ++ * descriptor is obtained by lookup, the descriptor is same as localdesc. ++ * So we cann't distinguish the receiver desc and local desc. ++ * + * @return the class descriptor read + * @throws IOException If an I/O error has occurred. + * @throws ClassNotFoundException If the Class of a serialized object used +@@ -920,6 +1020,27 @@ public class ObjectInputStream + protected ObjectStreamClass readClassDescriptor() + throws IOException, ClassNotFoundException + { ++ // fastSerializer ++ if (useFastSerializer) { ++ String name = readUTF(); ++ Class cl = null; ++ ObjectStreamClass desc = new ObjectStreamClass(name); ++ try { ++ // In order to match this method, we add an annotateClass method in ++ // writeClassDescriptor. ++ cl = resolveClass(desc); ++ } catch (ClassNotFoundException ex) { ++ // resolveClass is just used to obtain Class which required by lookup method ++ // and it will be called again later, so we don't throw ClassNotFoundException here. ++ return desc; ++ } ++ if (cl != null) { ++ desc = ObjectStreamClass.lookup(cl, true); ++ } ++ return desc; ++ } ++ ++ // Default deserialization. If the Class cannot be found, throw ClassNotFoundException. + ObjectStreamClass desc = new ObjectStreamClass(); + desc.readNonProxy(this); + return desc; +@@ -1935,17 +2056,40 @@ public class ObjectInputStream + + skipCustomData(); + +- try { +- totalObjectRefs++; +- depth++; +- desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false)); +- } finally { +- depth--; ++ totalObjectRefs++; ++ depth++; ++ ++ if (useFastSerializer) { ++ desc.initNonProxyFast(readDesc, resolveEx); ++ ObjectStreamClass superDesc = desc.getSuperDesc(); ++ long originDepth = depth - 1; ++ // Since desc is obtained from the lookup method, we will lose the depth and ++ // totalObjectRefs of superDesc. So we add a loop here to compute the depth ++ // and objectRef of superDesc. ++ while (superDesc != null && superDesc.forClass() != null) { ++ filterCheck(superDesc.forClass(), -1); ++ superDesc = superDesc.getSuperDesc(); ++ totalObjectRefs++; ++ depth++; ++ } ++ depth = originDepth; ++ } else { ++ try { ++ desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false)); ++ } finally { ++ depth--; ++ } + } + + handles.finish(descHandle); + passHandle = descHandle; + ++ if (Logging.fastSerLogger != null) { ++ Logging.fastSerLogger.fine( ++ "[Deserialize] useFastSerializer:{0}, Class name:{1}, SerialVersionUID:{2}, flags:{3}", ++ useFastSerializer, desc.getName(), desc.getSerialVersionUID(), desc.getFlags(this)); ++ } ++ + return desc; + } + +@@ -2334,21 +2478,25 @@ public class ObjectInputStream + desc.setPrimFieldValues(obj, primVals); + } + +- int objHandle = passHandle; +- ObjectStreamField[] fields = desc.getFields(false); +- Object[] objVals = new Object[desc.getNumObjFields()]; +- int numPrimFields = fields.length - objVals.length; +- for (int i = 0; i < objVals.length; i++) { +- ObjectStreamField f = fields[numPrimFields + i]; +- objVals[i] = readObject0(Object.class, f.isUnshared()); +- if (f.getField() != null) { +- handles.markDependency(objHandle, passHandle); ++ Object[] objVals = null; ++ int numObjFields = desc.getNumObjFields(); ++ if (numObjFields > 0) { ++ int objHandle = passHandle; ++ ObjectStreamField[] fields = desc.getFields(false); ++ objVals = new Object[numObjFields]; ++ int numPrimFields = fields.length - objVals.length; ++ for (int i = 0; i < objVals.length; i++) { ++ ObjectStreamField f = fields[numPrimFields + i]; ++ objVals[i] = readObject0(Object.class, f.isUnshared()); ++ if (f.getField() != null) { ++ handles.markDependency(objHandle, passHandle); ++ } + } ++ if (obj != null) { ++ desc.setObjFieldValues(obj, objVals); ++ } ++ passHandle = objHandle; + } +- if (obj != null) { +- desc.setObjFieldValues(obj, objVals); +- } +- passHandle = objHandle; + } + + /** +diff --git a/jdk/src/share/classes/java/io/ObjectOutputStream.java b/jdk/src/share/classes/java/io/ObjectOutputStream.java +index 6d29e3a1f..3890efc3e 100644 +--- a/jdk/src/share/classes/java/io/ObjectOutputStream.java ++++ b/jdk/src/share/classes/java/io/ObjectOutputStream.java +@@ -37,6 +37,8 @@ import java.util.concurrent.ConcurrentMap; + import static java.io.ObjectStreamClass.processQueue; + import java.io.SerialCallbackContext; + import sun.reflect.misc.ReflectUtil; ++import sun.misc.Unsafe; ++import sun.util.logging.PlatformLogger; + + /** + * An ObjectOutputStream writes primitive data types and graphs of Java objects +@@ -173,6 +175,24 @@ public class ObjectOutputStream + new ReferenceQueue<>(); + } + ++ private static class Logging { ++ /* ++ * Logger for FastSerializer. ++ * Setup the FastSerializer logger if it is set to FINE. ++ * (Assuming it will not change). ++ */ ++ static final PlatformLogger fastSerLogger; ++ static { ++ if (printFastSerializer) { ++ PlatformLogger fastSerLog = PlatformLogger.getLogger("fastSerializer"); ++ fastSerLogger = (fastSerLog != null && ++ fastSerLog.isLoggable(PlatformLogger.Level.FINE)) ? fastSerLog : null; ++ } else { ++ fastSerLogger = null; ++ } ++ } ++ } ++ + /** filter stream for handling block data conversion */ + private final BlockDataOutputStream bout; + /** obj -> wire handle map */ +@@ -214,6 +234,22 @@ public class ObjectOutputStream + new sun.security.action.GetBooleanAction( + "sun.io.serialization.extendedDebugInfo")).booleanValue(); + ++ private static final Unsafe UNSAFE = Unsafe.getUnsafe(); ++ ++ /** ++ * Value of "UseFastSerializer" property. The fastSerializer is turned ++ * on when it is true. ++ */ ++ private static final boolean useFastSerializer = UNSAFE.getUseFastSerializer(); ++ ++ /** ++ * value of "printFastSerializer" property, ++ * as true or false for printing FastSerializer logs. ++ */ ++ private static final boolean printFastSerializer = java.security.AccessController.doPrivileged( ++ new sun.security.action.GetBooleanAction( ++ "printFastSerializer")).booleanValue(); ++ + /** + * Creates an ObjectOutputStream that writes to the specified OutputStream. + * This constructor writes the serialization stream header to the +@@ -327,6 +363,9 @@ public class ObjectOutputStream + * object are written transitively so that a complete equivalent graph of + * objects can be reconstructed by an ObjectInputStream. + * ++ * The difference between fastSerialzation and default serialization is the ++ * descriptor serialization. The data serialization is same with each other. ++ * + *

Exceptions are thrown for problems with the OutputStream and for + * classes that should not be serialized. All exceptions are fatal to the + * OutputStream, which is left in an indeterminate state, and it is up to +@@ -633,7 +672,11 @@ public class ObjectOutputStream + * stream + */ + protected void writeStreamHeader() throws IOException { +- bout.writeShort(STREAM_MAGIC); ++ if (useFastSerializer) { ++ bout.writeShort(STREAM_MAGIC_FAST); ++ } else { ++ bout.writeShort(STREAM_MAGIC); ++ } + bout.writeShort(STREAM_VERSION); + } + +@@ -648,6 +691,9 @@ public class ObjectOutputStream + * By default, this method writes class descriptors according to the format + * defined in the Object Serialization specification. + * ++ * In fastSerializer mode, we will only write the classname to the stream. ++ * The annotateClass is used to match the resolveClass in readClassDescriptor. ++ * + *

Note that this method will only be called if the ObjectOutputStream + * is not using the old serialization stream format (set by calling + * ObjectOutputStream's useProtocolVersion method). If this +@@ -665,7 +711,14 @@ public class ObjectOutputStream + protected void writeClassDescriptor(ObjectStreamClass desc) + throws IOException + { +- desc.writeNonProxy(this); ++ if (useFastSerializer) { ++ writeUTF(desc.getName()); ++ // The annotateClass is used to match the resolveClass called in ++ // readClassDescriptor. ++ annotateClass(desc.forClass()); ++ } else { ++ desc.writeNonProxy(this); ++ } + } + + /** +@@ -1275,9 +1328,21 @@ public class ObjectOutputStream + bout.writeByte(TC_CLASSDESC); + handles.assign(unshared ? null : desc); + ++ if (Logging.fastSerLogger != null) { ++ Logging.fastSerLogger.fine( ++ "[Serialize] useFastSerializer:{0}, Class name:{1}, SerialVersionUID:{2}, flags:{3}, protocol:{4}", ++ useFastSerializer, desc.getName(), desc.getSerialVersionUID(), desc.getFlags(this), protocol); ++ } ++ + if (protocol == PROTOCOL_VERSION_1) { + // do not invoke class descriptor write hook with old protocol +- desc.writeNonProxy(this); ++ if (useFastSerializer) { ++ // only write name and annotate class when using FastSerializer ++ writeUTF(desc.getName()); ++ annotateClass(desc.forClass()); ++ } else { ++ desc.writeNonProxy(this); ++ } + } else { + writeClassDescriptor(desc); + } +@@ -1291,7 +1356,9 @@ public class ObjectOutputStream + bout.setBlockDataMode(false); + bout.writeByte(TC_ENDBLOCKDATA); + +- writeClassDesc(desc.getSuperDesc(), false); ++ if (!useFastSerializer) { ++ writeClassDesc(desc.getSuperDesc(), false); ++ } + } + + /** +diff --git a/jdk/src/share/classes/java/io/ObjectStreamClass.java b/jdk/src/share/classes/java/io/ObjectStreamClass.java +index 64453b25a..fce3c3475 100644 +--- a/jdk/src/share/classes/java/io/ObjectStreamClass.java ++++ b/jdk/src/share/classes/java/io/ObjectStreamClass.java +@@ -280,6 +280,40 @@ public class ObjectStreamClass implements Serializable { + return suid.longValue(); + } + ++ /** ++ * Return the flags for this class described by this descriptor. The flags ++ * means a set of bit masks for ObjectStreamClass, which indicate the status ++ * of SC_WRITE_METHOD, SC_SERIALIZABLE, SC_EXTERNALIZABLE, SC_BLOCK_DATA and ++ * SC_ENUM. ++ * ++ * @param serialStream ObjectOutputStream or ObjectInputStream ++ * ++ * @return the flags for this class described by this descriptor ++ */ ++ public byte getFlags(Object serialStream) { ++ byte flags = 0; ++ if (externalizable) { ++ flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; ++ if (serialStream instanceof ObjectOutputStream) { ++ int protocol = ((ObjectOutputStream)serialStream).getProtocolVersion(); ++ if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) { ++ flags |= ObjectStreamConstants.SC_BLOCK_DATA; ++ } ++ } else if (serialStream instanceof ObjectInputStream) { ++ flags |= ObjectStreamConstants.SC_BLOCK_DATA; ++ } ++ } else if (serializable) { ++ flags |= ObjectStreamConstants.SC_SERIALIZABLE; ++ } ++ if (hasWriteObjectData) { ++ flags |= ObjectStreamConstants.SC_WRITE_METHOD; ++ } ++ if (isEnum) { ++ flags |= ObjectStreamConstants.SC_ENUM; ++ } ++ return flags; ++ } ++ + /** + * Return the class in the local VM that this version is mapped to. Null + * is returned if there is no corresponding local class. +@@ -570,6 +604,15 @@ public class ObjectStreamClass implements Serializable { + ObjectStreamClass() { + } + ++ /** ++ * Create a blank class descriptor with name. It is only used ++ * in fastSerialize path. ++ * @param name class name ++ */ ++ ObjectStreamClass(String name) { ++ this.name = name; ++ } ++ + /** + * Creates a PermissionDomain that grants no permission. + */ +@@ -756,6 +799,44 @@ public class ObjectStreamClass implements Serializable { + initialized = true; + } + ++ /** ++ * Initializes class descriptor representing a non-proxy class. ++ * Used in fast serialization mode. ++ */ ++ void initNonProxyFast(ObjectStreamClass model, ++ ClassNotFoundException resolveEx) ++ { ++ this.cl = model.cl; ++ this.resolveEx = resolveEx; ++ this.superDesc = model.superDesc; ++ name = model.name; ++ this.suid = model.suid; ++ isProxy = false; ++ isEnum = model.isEnum; ++ serializable = model.serializable; ++ externalizable = model.externalizable; ++ hasBlockExternalData = model.hasBlockExternalData; ++ hasWriteObjectData = model.hasWriteObjectData; ++ fields = model.fields; ++ primDataSize = model.primDataSize; ++ numObjFields = model.numObjFields; ++ ++ writeObjectMethod = model.writeObjectMethod; ++ readObjectMethod = model.readObjectMethod; ++ readObjectNoDataMethod = model.readObjectNoDataMethod; ++ writeReplaceMethod = model.writeReplaceMethod; ++ readResolveMethod = model.readResolveMethod; ++ if (deserializeEx == null) { ++ deserializeEx = model.deserializeEx; ++ } ++ domains = model.domains; ++ cons = model.cons; ++ fieldRefl = model.fieldRefl; ++ localDesc = model; ++ ++ initialized = true; ++ } ++ + /** + * Reads non-proxy class descriptor information from given input stream. + * The resulting class descriptor is not fully functional; it can only be +diff --git a/jdk/src/share/classes/java/io/ObjectStreamConstants.java b/jdk/src/share/classes/java/io/ObjectStreamConstants.java +index 23f72b436..59179a6ec 100644 +--- a/jdk/src/share/classes/java/io/ObjectStreamConstants.java ++++ b/jdk/src/share/classes/java/io/ObjectStreamConstants.java +@@ -38,6 +38,11 @@ public interface ObjectStreamConstants { + */ + final static short STREAM_MAGIC = (short)0xaced; + ++ /** ++ * Magic number that is written to the stream header when using fastserilizer. ++ */ ++ static final short STREAM_MAGIC_FAST = (short)0xdeca; ++ + /** + * Version number that is written to the stream header. + */ +diff --git a/jdk/src/share/classes/sun/misc/Unsafe.java b/jdk/src/share/classes/sun/misc/Unsafe.java +index 99e465802..92fb01669 100644 +--- a/jdk/src/share/classes/sun/misc/Unsafe.java ++++ b/jdk/src/share/classes/sun/misc/Unsafe.java +@@ -433,6 +433,8 @@ public final class Unsafe { + /** @see #putByte(long, byte) */ + public native void putDouble(long address, double x); + ++ public native boolean getUseFastSerializer(); ++ + /** + * Fetches a native pointer from a given memory address. If the address is + * zero, or does not point into a block obtained from {@link diff --git a/fix-incorrect-offset-for-oop-field-with-weak-memory-.patch b/fix-incorrect-offset-for-oop-field-with-weak-memory-.patch deleted file mode 100644 index 40df6ba61c34e584bbb051bf2d36ae55768d2846..0000000000000000000000000000000000000000 --- a/fix-incorrect-offset-for-oop-field-with-weak-memory-.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 7c73365615f00951272310db44dec2939b91b48e Mon Sep 17 00:00:00 2001 -Date: Wed, 19 Feb 2020 19:09:39 +0000 -Subject: [PATCH] fix incorrect offset for oop field with weak memory model - -Summary: : add loadload membar in fast_storefield and fast_accessfield to avoid loading a incorrect offset -LLT: N/A -Bug url: N/A ---- - hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp -index 5a619566ae..aa9545ee9c 100644 ---- a/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp -+++ b/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp -@@ -2922,6 +2922,8 @@ void TemplateTable::fast_storefield(TosState state) - // access constant pool cache - __ get_cache_and_index_at_bcp(r2, r1, 1); - -+ __ membar(MacroAssembler::LoadLoad); -+ - // test for volatile with r3 - __ ldrw(r3, Address(r2, in_bytes(base + - ConstantPoolCacheEntry::flags_offset()))); -@@ -3013,6 +3015,9 @@ void TemplateTable::fast_accessfield(TosState state) - - // access constant pool cache - __ get_cache_and_index_at_bcp(r2, r1, 1); -+ -+ __ membar(MacroAssembler::LoadLoad); -+ - __ ldr(r1, Address(r2, in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::f2_offset()))); - __ ldrw(r3, Address(r2, in_bytes(ConstantPoolCache::base_offset() + --- -2.12.3 - diff --git a/generate_source_tarball.sh b/generate_source_tarball.sh new file mode 100755 index 0000000000000000000000000000000000000000..cf0e622446e51251e5a799806c141faa9269e20a --- /dev/null +++ b/generate_source_tarball.sh @@ -0,0 +1,154 @@ +#!/bin/bash +# Generates the 'source tarball' for JDK 8 projects. +# +# Example: +# When used from local repo set REPO_ROOT pointing to file:// with your repo +# If your local repo follows upstream forests conventions, it may be enough to set OPENJDK_URL +# If you want to use a local copy of patch PR3756, set the path to it in the PR3756 variable +# +# In any case you have to set PROJECT_NAME REPO_NAME and VERSION. eg: +# PROJECT_NAME=jdk8u OR aarch64-port +# REPO_NAME=jdk8u60 OR jdk8u60 +# VERSION=jdk8u60-b27 OR aarch64-jdk8u65-b17 OR for head, keyword 'tip' should do the job there +# +# They are used to create correct name and are used in construction of sources url (unless REPO_ROOT is set) + +# This script creates a single source tarball out of the repository +# based on the given tag and removes code not allowed in fedora/rhel. For +# consistency, the source tarball will always contain 'openjdk' as the top +# level folder, name is created, based on parameter +# + +if [ ! "x$PR3756" = "x" ] ; then + if [ ! -f "$PR3756" ] ; then + echo "You have specified PR3756 as $PR3756 but it does not exists. exiting" + exit 1 + fi +fi +set -e + +OPENJDK_URL_DEFAULT=http://hg.openjdk.java.net +COMPRESSION_DEFAULT=xz +# jdk is last for its size +REPOS_DEFAULT="hotspot corba jaxws jaxp langtools nashorn jdk" + +if [ "x$1" = "xhelp" ] ; then + echo -e "Behaviour may be specified by setting the following variables:\n" + echo "VERSION - the version of the specified OpenJDK project" + echo "PROJECT_NAME -- the name of the OpenJDK project being archived (optional; only needed by defaults)" + echo "REPO_NAME - the name of the OpenJDK repository (optional; only needed by defaults)" + echo "OPENJDK_URL - the URL to retrieve code from (optional; defaults to ${OPENJDK_URL_DEFAULT})" + echo "COMPRESSION - the compression type to use (optional; defaults to ${COMPRESSION_DEFAULT})" + echo "FILE_NAME_ROOT - name of the archive, minus extensions (optional; defaults to PROJECT_NAME-REPO_NAME-VERSION)" + echo "REPO_ROOT - the location of the Mercurial repository to archive (optional; defaults to OPENJDK_URL/PROJECT_NAME/REPO_NAME)" + echo "PR3756 - the path to the PR3756 patch to apply (optional; downloaded if unavailable)" + echo "REPOS - specify the repositories to use (optional; defaults to ${REPOS_DEFAULT})" + exit 1; +fi + + +if [ "x$VERSION" = "x" ] ; then + echo "No VERSION specified" + exit -2 +fi +echo "Version: ${VERSION}" + +# REPO_NAME is only needed when we default on REPO_ROOT and FILE_NAME_ROOT +if [ "x$FILE_NAME_ROOT" = "x" -o "x$REPO_ROOT" = "x" ] ; then + if [ "x$PROJECT_NAME" = "x" ] ; then + echo "No PROJECT_NAME specified" + exit -1 + fi + echo "Project name: ${PROJECT_NAME}" + if [ "x$REPO_NAME" = "x" ] ; then + echo "No REPO_NAME specified" + exit -3 + fi + echo "Repository name: ${REPO_NAME}" +fi + +if [ "x$OPENJDK_URL" = "x" ] ; then + OPENJDK_URL=${OPENJDK_URL_DEFAULT} + echo "No OpenJDK URL specified; defaulting to ${OPENJDK_URL}" +else + echo "OpenJDK URL: ${OPENJDK_URL}" +fi + +if [ "x$COMPRESSION" = "x" ] ; then +# rhel 5 needs tar.gz + COMPRESSION=${COMPRESSION_DEFAULT} +fi +echo "Creating a tar.${COMPRESSION} archive" + +if [ "x$FILE_NAME_ROOT" = "x" ] ; then + FILE_NAME_ROOT=${PROJECT_NAME}-${REPO_NAME}-${VERSION} + echo "No file name root specified; default to ${FILE_NAME_ROOT}" +fi +if [ "x$REPO_ROOT" = "x" ] ; then + REPO_ROOT="${OPENJDK_URL}/${PROJECT_NAME}/${REPO_NAME}" + echo "No repository root specified; default to ${REPO_ROOT}" +fi; + +mkdir "${FILE_NAME_ROOT}" +pushd "${FILE_NAME_ROOT}" + +echo "Cloning ${VERSION} root repository from ${REPO_ROOT}" +hg clone ${REPO_ROOT} openjdk -r ${VERSION} +pushd openjdk + + +if [ "x$REPOS" = "x" ] ; then + repos=${REPOS_DEFAULT} + echo "No repositories specified; defaulting to ${repos}" +else + repos=$REPOS + echo "Repositories: ${repos}" +fi; + +for subrepo in $repos +do + echo "Cloning ${VERSION} ${subrepo} repository from ${REPO_ROOT}" + hg clone ${REPO_ROOT}/${subrepo} -r ${VERSION} +done + +if [ -d jdk ]; then +echo "Removing EC source code we don't build" +rm -vf jdk/src/share/native/sun/security/ec/impl/ec2.h +rm -vf jdk/src/share/native/sun/security/ec/impl/ec2_163.c +rm -vf jdk/src/share/native/sun/security/ec/impl/ec2_193.c +rm -vf jdk/src/share/native/sun/security/ec/impl/ec2_233.c +rm -vf jdk/src/share/native/sun/security/ec/impl/ec2_aff.c +rm -vf jdk/src/share/native/sun/security/ec/impl/ec2_mont.c +rm -vf jdk/src/share/native/sun/security/ec/impl/ecp_192.c +rm -vf jdk/src/share/native/sun/security/ec/impl/ecp_224.c + +echo "Syncing EC list with NSS" + +if [ "x$PR3756" = "x" ] ; then +# get pr3756.patch (from http://icedtea.classpath.org/hg/icedtea8) from most correct tag +# Do not push it or publish it (see http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3756) + wget http://icedtea.classpath.org/hg/icedtea8/raw-file/tip/patches/pr3756.patch + patch -Np1 < pr3756.patch + rm pr3756.patch +else + echo "Applying ${PR3756}" + patch -Np1 < $PR3756 +fi; +fi +find . -name '*.orig' -exec rm -vf '{}' ';' + +popd +echo "Compressing remaining forest" +if [ "X$COMPRESSION" = "Xxz" ] ; then + SWITCH=cJf +else + SWITCH=czf +fi +TARBALL_NAME=${FILE_NAME_ROOT}.tar.${COMPRESSION} +tar --exclude-vcs -$SWITCH ${TARBALL_NAME} openjdk +mv ${TARBALL_NAME} .. + +popd +echo "Done. You may want to remove the uncompressed version." + + diff --git a/java-1.8.0-openjdk.spec b/java-1.8.0-openjdk.spec index 3faea103f5d81b14a347e14b4d0fd63202984fe3..95709ad9d6a365dbda67f8b311d0010c9f460d48 100644 --- a/java-1.8.0-openjdk.spec +++ b/java-1.8.0-openjdk.spec @@ -21,9 +21,6 @@ # Enable release builds by default on relevant arches. %bcond_without release -# Do not check unpackaged files -%define _unpackaged_files_terminate_build 0 - # The -g flag says to use strip -g instead of full strip on DSOs or EXEs. # This fixes detailed NMT and other tools which need minimal debug info. %global _find_debuginfo_opts -g @@ -32,7 +29,6 @@ # also necessary when passing it as parameter to other macros. If not macro, then it is considered a switch # see the difference between global and define: # See https://github.com/rpm-software-management/rpm/issues/127 to comments at "pmatilai commented on Aug 18, 2017" -# (initiated in https://bugzilla.redhat.com/show_bug.cgi?id=1482192) %global debug_suffix_unquoted -slowdebug # quoted one for shell operations %global debug_suffix "%{debug_suffix_unquoted}" @@ -56,11 +52,12 @@ %endif %global aarch64 aarch64 +%global jit_arches x86_64 %{aarch64} +%global sa_arches x86_64 %{aarch64} +%global jfr_arches x86_64 %{aarch64} # By default, we build a debug build during main build on JIT architectures -%if %{with slowdebug} %global include_debug_build 1 -%endif %if %{include_debug_build} %global build_loop2 %{debug_suffix} @@ -74,7 +71,11 @@ # is expected in one single case at the end of the build %global rev_build_loop %{build_loop2} %{build_loop1} +%ifarch %{jit_arches} %global bootstrap_build 1 +%else +%global bootstrap_build 0 +%endif %global release_targets images zip-docs # No docs nor bootcycle for debug builds @@ -96,24 +97,12 @@ %global NSS_LIBDIR %(pkg-config --variable=libdir nss) %global NSS_LIBS %(pkg-config --libs nss) %global NSS_CFLAGS %(pkg-config --cflags nss-softokn) -# see https://bugzilla.redhat.com/show_bug.cgi?id=1332456 %global NSSSOFTOKN_BUILDTIME_NUMBER %(pkg-config --modversion nss-softokn || : ) %global NSS_BUILDTIME_NUMBER %(pkg-config --modversion nss || : ) # this is workaround for processing of requires during srpm creation %global NSSSOFTOKN_BUILDTIME_VERSION %(if [ "x%{NSSSOFTOKN_BUILDTIME_NUMBER}" == "x" ] ; then echo "" ;else echo ">= %{NSSSOFTOKN_BUILDTIME_NUMBER}" ;fi) %global NSS_BUILDTIME_VERSION %(if [ "x%{NSS_BUILDTIME_NUMBER}" == "x" ] ; then echo "" ;else echo ">= %{NSS_BUILDTIME_NUMBER}" ;fi) - -# Fix for https://bugzilla.redhat.com/show_bug.cgi?id=1111349. -# See also https://bugzilla.redhat.com/show_bug.cgi?id=1590796 -# as to why some libraries *cannot* be excluded. In particular, -# these are: -# libjsig.so, libjava.so, libjawt.so, libjvm.so and libverify.so -%global _privatelibs libatk-wrapper[.]so.*|libattach[.]so.*|libawt_headless[.]so.*|libawt[.]so.*|libawt_xawt[.]so.*|libdt_socket[.]so.*|libfontmanager[.]so.*|libhprof[.]so.*|libinstrument[.]so.*|libj2gss[.]so.*|libj2pcsc[.]so.*|libj2pkcs11[.]so.*|libjaas_unix[.]so.*|libjava_crw_demo[.]so.*|libjavajpeg[.]so.*|libjdwp[.]so.*|libjli[.]so.*|libjsdt[.]so.*|libjsoundalsa[.]so.*|libjsound[.]so.*|liblcms[.]so.*|libmanagement[.]so.*|libmlib_image[.]so.*|libnet[.]so.*|libnio[.]so.*|libnpt[.]so.*|libsaproc[.]so.*|libsctp[.]so.*|libsplashscreen[.]so.*|libsunec[.]so.*|libunpack[.]so.*|libzip[.]so.*|lib[.]so\\(SUNWprivate_.* - -%global __provides_exclude ^(%{_privatelibs})$ -%global __requires_exclude ^(%{_privatelibs})$ - # In some cases, the arch used by the JDK does # not match _arch. # Also, in some cases, the machine name used by SystemTap @@ -127,7 +116,11 @@ %global stapinstall arm64 %endif +%ifarch %{jit_arches} %global with_systemtap 1 +%else +%global with_systemtap 0 +%endif # New Version-String scheme-style defines %global majorver 8 @@ -152,14 +145,11 @@ %global origin openjdk %global origin_nice OpenJDK %global top_level_dir_name %{origin} -# note, following three variables are sedded from update_sources if used correctly. Hardcode them rather there. -%global shenandoah_project aarch64-port -%global shenandoah_repo jdk8u-shenandoah -%global shenandoah_revision aarch64-shenandoah-jdk8u262-b05 # Define old aarch64/jdk8u tree variables for compatibility -%global project %{shenandoah_project} -%global repo %{shenandoah_repo} -%global revision %{shenandoah_revision} +%global project aarch64-port +%global repo jdk8u-shenandoah +%global revision aarch64-shenandoah-jdk8u262-b10 +%global full_revision %{project}-%{repo}-%{revision} # Define IcedTea version used for SystemTap tapsets and desktop files %global icedteaver 3.15.0 @@ -170,7 +160,7 @@ # eg jdk8u60-b27 -> b27 %global buildver %(VERSION=%{revision}; echo ${VERSION##*-}) # priority must be 7 digits in total. The expression is workarounding tip -%global priority %(TIP=1800%{updatever}; echo ${TIP/tip/999}) +%global priority 1800%{updatever} %global javaver 1.%{majorver}.0 @@ -185,6 +175,16 @@ %define uniquejavadocdir() %{expand:%{fullversion}%{?1}} # main id and dir of this jdk %define uniquesuffix() %{expand:%{fullversion}.%{_arch}%{?1}} + +%global _privatelibs libatk-wrapper[.]so.*|libattach[.]so.*|libawt_headless[.]so.*|libawt[.]so.*|libawt_xawt[.]so.*|libdt_socket[.]so.*|libfontmanager[.]so.*|libhprof[.]so.*|libinstrument[.]so.*|libj2gss[.]so.*|libj2pcsc[.]so.*|libj2pkcs11[.]so.*|libjaas_unix[.]so.*|libjava_crw_demo[.]so.*|libjavajpeg[.]so.*|libjdwp[.]so.*|libjli[.]so.*|libjsdt[.]so.*|libjsoundalsa[.]so.*|libjsound[.]so.*|liblcms[.]so.*|libmanagement[.]so.*|libmlib_image[.]so.*|libnet[.]so.*|libnio[.]so.*|libnpt[.]so.*|libsaproc[.]so.*|libsctp[.]so.*|libsplashscreen[.]so.*|libsunec[.]so.*|libunpack[.]so.*|libzip[.]so.*|lib[.]so\\(SUNWprivate_.* +%global _publiclibs libjawt[.]so.*|libjava[.]so.*|libjvm[.]so.*|libverify[.]so.*|libjsig[.]so.* + +%global __provides_exclude ^(%{_privatelibs})$ +%global __requires_exclude ^(%{_privatelibs})$ +# Never generate lib-style provides/requires for slowdebug packages +%global __provides_exclude_from ^.*/%{uniquesuffix -- %{debug_suffix_unquoted}}/.*$ +%global __requires_exclude_from ^.*/%{uniquesuffix -- %{debug_suffix_unquoted}}/.*$ + %global etcjavasubdir %{_sysconfdir}/java/java-%{javaver}-%{origin} %define etcjavadir() %{expand:%{etcjavasubdir}/%{uniquesuffix -- %{?1}}} @@ -329,6 +329,9 @@ alternatives \\ --slave %{_bindir}/jconsole jconsole %{sdkbindir -- %{?1}}/jconsole \\ --slave %{_bindir}/jdb jdb %{sdkbindir -- %{?1}}/jdb \\ --slave %{_bindir}/jdeps jdeps %{sdkbindir -- %{?1}}/jdeps \\ +%ifarch %{jfr_arches} + --slave %{_bindir}/jfr jfr %{sdkbindir -- %{?1}}/jfr \\ +%endif --slave %{_bindir}/jhat jhat %{sdkbindir -- %{?1}}/jhat \\ --slave %{_bindir}/jinfo jinfo %{sdkbindir -- %{?1}}/jinfo \\ --slave %{_bindir}/jmap jmap %{sdkbindir -- %{?1}}/jmap \\ @@ -542,8 +545,10 @@ exit 0 %{_mandir}/man1/policytool-%{uniquesuffix -- %{?1}}.1* %{_jvmdir}/%{jredir -- %{?1}}/lib/security/nss.cfg %config(noreplace) %{etcjavadir -- %{?1}}/lib/security/nss.cfg +%ifarch %{jit_arches} %attr(444, root, root) %ghost %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/server/classes.jsa %attr(444, root, root) %ghost %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/client/classes.jsa +%endif %dir %{etcjavasubdir} %dir %{etcjavadir -- %{?1}} %dir %{etcjavadir -- %{?1}}/lib @@ -582,7 +587,9 @@ exit 0 %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libnet.so %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libnio.so %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libnpt.so +%ifarch %{sa_arches} %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libsaproc.so +%endif %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libsctp.so %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libsunec.so %{_jvmdir}/%{jredir -- %{?1}}/lib/%{archinstall}/libunpack.so @@ -621,12 +628,20 @@ exit 0 %{_jvmdir}/%{jredir -- %{?1}}/lib/ext/sunjce_provider.jar %{_jvmdir}/%{jredir -- %{?1}}/lib/ext/sunpkcs11.jar %{_jvmdir}/%{jredir -- %{?1}}/lib/ext/zipfs.jar +%ifarch %{jfr_arches} +%{_jvmdir}/%{jredir -- %{?1}}/lib/jfr.jar +%{_jvmdir}/%{jredir -- %{?1}}/lib/jfr/default.jfc +%{_jvmdir}/%{jredir -- %{?1}}/lib/jfr/profile.jfc +%endif %dir %{_jvmdir}/%{jredir -- %{?1}}/lib/images %dir %{_jvmdir}/%{jredir -- %{?1}}/lib/images/cursors %dir %{_jvmdir}/%{jredir -- %{?1}}/lib/management %dir %{_jvmdir}/%{jredir -- %{?1}}/lib/cmm %dir %{_jvmdir}/%{jredir -- %{?1}}/lib/ext +%ifarch %{jfr_arches} +%dir %{_jvmdir}/%{jredir -- %{?1}}/lib/jfr +%endif } %define files_devel() %{expand: @@ -654,6 +669,9 @@ exit 0 %{_jvmdir}/%{sdkdir -- %{?1}}/bin/jconsole %{_jvmdir}/%{sdkdir -- %{?1}}/bin/jdb %{_jvmdir}/%{sdkdir -- %{?1}}/bin/jdeps +%ifarch %{jfr_arches} +%{_jvmdir}/%{sdkdir -- %{?1}}/bin/jfr +%endif %{_jvmdir}/%{sdkdir -- %{?1}}/bin/jhat %{_jvmdir}/%{sdkdir -- %{?1}}/bin/jinfo %{_jvmdir}/%{sdkdir -- %{?1}}/bin/jjs @@ -689,7 +707,9 @@ exit 0 %{_jvmdir}/%{sdkdir -- %{?1}}/lib/ir.idl %{_jvmdir}/%{sdkdir -- %{?1}}/lib/jconsole.jar %{_jvmdir}/%{sdkdir -- %{?1}}/lib/orb.idl +%ifarch %{sa_arches} %{_jvmdir}/%{sdkdir -- %{?1}}/lib/sa-jdi.jar +%endif %{_jvmdir}/%{sdkdir -- %{?1}}/lib/dt.jar %{_jvmdir}/%{sdkdir -- %{?1}}/lib/jexec %{_jvmdir}/%{sdkdir -- %{?1}}/lib/tools.jar @@ -790,7 +810,7 @@ Requires: ca-certificates # Require javapackages-filesystem for ownership of /usr/lib/jvm/ Requires: javapackages-filesystem # Require zone-info data provided by tzdata-java sub-package -Requires: tzdata-java >= 2015d +Requires: tzdata-java >= 2020a # libsctp.so.1 is being `dlopen`ed on demand Requires: lksctp-tools%{?_isa} # there is a need to depend on the exact version of NSS @@ -823,10 +843,6 @@ Provides: java-%{javaver}-%{origin}-headless%{?1} = %{epoch}:%{version}-%{releas Provides: java-%{javaver}-headless%{?1} = %{epoch}:%{version}-%{release} Provides: java-%{origin}-headless%{?1} = %{epoch}:%{version}-%{release} Provides: java-headless%{?1} = %{epoch}:%{version}-%{release} - -# https://bugzilla.redhat.com/show_bug.cgi?id=1312019 -Provides: /usr/bin/jjs - } %define java_devel_rpo() %{expand: @@ -899,7 +915,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 9 +Release: 0 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -925,17 +941,9 @@ Group: Development/Languages # The PCSClite headers are under a BSD with advertising license # The elliptic curve cryptography (ECC) source code is licensed under the LGPLv2.1 or any later version License: ASL 1.1 and ASL 2.0 and BSD and BSD with advertising and GPL+ and GPLv2 and GPLv2 with exceptions and IJG and LGPLv2+ and MIT and MPLv2.0 and Public Domain and W3C and zlib -URL: http://openjdk.java.net - -# Shenandoah HotSpot -# aarch64-port/jdk8u-shenandoah contains an integration forest of -# OpenJDK 8u, the aarch64 port and Shenandoah -# To regenerate, use: -# VERSION=%%{shenandoah_revision} -# FILE_NAME_ROOT=%%{shenandoah_project}-%%{shenandoah_repo}-${VERSION} -# REPO_ROOT= generate_source_tarball.sh -# where the source is obtained from http://hg.openjdk.java.net/%%{project}/%%{repo} -Source0: %{shenandoah_revision}.tar.xz +URL: http://openjdk.java.net/ + +Source0: %{full_revision}.tar.xz # Custom README for -src subpackage Source2: README.md @@ -1010,7 +1018,6 @@ Patch75: Add-ability-to-configure-third-port-for-remote-JMX.patch Patch76: 8203196-C1-emits-incorrect-code-due-to-integer-overf.patch Patch77: 8190332-PngReader-throws-NegativeArraySizeException-.patch Patch78: 8171410-aarch64-long-multiplyExact-shifts-by-31-inst.patch -Patch81: fix-incorrect-offset-for-oop-field-with-weak-memory-.patch Patch83: 8204947-Port-ShenandoahTaskTerminator-to-mainline-an.patch Patch85: 8139041-Redundant-DMB-instructions.patch @@ -1019,6 +1026,14 @@ Patch86: 6858051-Create-GC-worker-threads-dynamically.patch Patch87: 6858051-Add-a-switch-for-the-dynamic-thread-related-.patch Patch88: dismiss-warnings-in-GCC-8.X.patch +# 8u262 +Patch89: 8144993-Elide-redundant-memory-barrier-after-AllocationNode.patch +Patch90: 8223504-improve-performance-of-forall-loops-by-better.patch +Patch91: add-vm-option-BoxTypeCachedMax-for-Integer-and-Long-cache.patch +Patch92: 8080289-8040213-8189067-move-the-store-out-of-the-loop.patch +Patch93: fast-serializer-jdk8.patch +Patch94: 8182397-race-in-field-updates.patch + ############################################# # # Upstreamable patches @@ -1342,7 +1357,6 @@ if [ %{include_debug_build} -eq 0 -a %{include_normal_build} -eq 0 ] ; then exit 13 fi %setup -q -c -n %{uniquesuffix ""} -T -a 0 -# https://bugzilla.redhat.com/show_bug.cgi?id=1189084 prioritylength=`expr length %{priority}` if [ $prioritylength -ne 7 ] ; then echo "priority must be 7 digits in total, violated" @@ -1401,12 +1415,17 @@ pushd %{top_level_dir_name} %patch76 -p1 %patch77 -p1 %patch78 -p1 -%patch81 -p1 %patch83 -p1 %patch85 -p1 %patch86 -p1 %patch87 -p1 %patch88 -p1 +%patch89 -p1 +%patch90 -p1 +%patch91 -p1 +%patch92 -p1 +%patch93 -p1 +%patch94 -p1 popd @@ -1505,10 +1524,18 @@ mkdir -p %{buildoutputdir -- $suffix} pushd %{buildoutputdir -- $suffix} bash ${top_srcdir_abs_path}/configure \ +%ifarch %{jfr_arches} + --enable-jfr \ +%endif --with-native-debug-symbols=internal \ --with-milestone="fcs" \ --with-update-version=%{updatever} \ --with-build-number=%{buildver} \ + --with-company-name="Boole" \ + --with-vendor-name="Boole" \ + --with-vendor-url="https://openeuler.org/" \ + --with-vendor-bug-url="https://gitee.com/src-openeuler/openjdk-1.8.0/issues/" \ + --with-vendor-vm-bug-url="https://gitee.com/src-openeuler/openjdk-1.8.0/issues/" \ --with-debug-level=$debugbuild \ --enable-unlimited-crypto \ --with-zlib=system \ @@ -1538,7 +1565,6 @@ make \ # the build (erroneously) removes read permissions from some jars # this is a regression in OpenJDK 7 (our compiler): -# http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1437 find images/%{jdkimage} -iname '*.jar' -exec chmod ugo+r {} \; chmod ugo+r images/%{jdkimage}/lib/ct.sym @@ -1629,9 +1655,7 @@ done # Make sure gdb can do a backtrace based on line numbers on libjvm.so # javaCalls.cpp:58 should map to: # http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/ff3b27e6bcc2/src/share/vm/runtime/javaCalls.cpp#l58 -# Using line number 1 might cause build problems. See: -# https://bugzilla.redhat.com/show_bug.cgi?id=1539664 -# https://bugzilla.redhat.com/show_bug.cgi?id=1538767 +# Using line number 1 might cause build problems. gdb -q "$JAVA_HOME/bin/java" < --- see https://bugzilla.redhat.com/show_bug.cgi?id=1038092 for whole issue --- see https://bugzilla.redhat.com/show_bug.cgi?id=1290388 for pretrans over pre -- if copy-jdk-configs is in transaction, it installs in pretrans to temp -- if copy_jdk_configs is in temp, then it means that copy-jdk-configs is in transaction and so is -- preferred over one in %%{_libexecdir}. If it is not in transaction, then depends @@ -2025,6 +2045,17 @@ require "copy_jdk_configs.lua" %endif %changelog +* Thu Jul 18 2020 jdkboy - 1:1.8.0.262-b10.0 +- Update to aarch64-shenandoah-jdk8u-8u262-b10 +- add 8144993-Elide-redundant-memory-barrier-after-AllocationNode.patch +- add 8223504-improve-performance-of-forall-loops-by-better.patch +- add add-vm-option-BoxTypeCachedMax-for-Integer-and-Long-cache.patch +- add 8080289-8040213-8189067-move-the-store-out-of-the-loop.patch +- add fast-serializer-jdk8.patch +- add 8182397-race-in-field-updates.patch +- add --with-company-name="Boole" +- remove fix-incorrect-offset-for-oop-field-with-weak-memory-.patch + * Thu Jun 11 2020 jdkboy - 1:1.8.0.262-b05.9 - Update to aarch64-shenandoah-jdk8u-8u262-b05 diff --git a/sources b/sources new file mode 100644 index 0000000000000000000000000000000000000000..e88b018a3f7e585e8560c5f770db945b730028fe --- /dev/null +++ b/sources @@ -0,0 +1,2 @@ +SHA512 (tapsets-icedtea-3.15.0.tar.xz) = c752a197cb3d812d50c35e11e4722772be40096c81d2a57933e0d9b8a3c708b9c157b8108a4e33a06ca7bb81648170994408c75d6f69d5ff12785d0c31009671 +SHA512 (aarch64-port-jdk8u-shenandoah-aarch64-shenandoah-jdk8u262-b10.tar.xz) = ed4e67d3b6254113cbe93f47feae2dbbc205995b7a0ec613c87d1c9fc037c9275f332bcdb9c4b7a158e27dfbecb4772671b64084e47f5d1b25ba4677b27c7096 diff --git a/update_main_sources.sh b/update_main_sources.sh new file mode 100755 index 0000000000000000000000000000000000000000..08f735a7cf2e36df83d234cac68b57cef0d465e7 --- /dev/null +++ b/update_main_sources.sh @@ -0,0 +1,95 @@ +#!/bin/bash -x +# Generates the 'source tarball' for JDK 8 projects and update spec infrastructure +# By default, this script regenerate source as they are currently used. +# so if the version of sources change, this file changes and is pushed +# +# In any case you have to set PROJECT_NAME REPO_NAME and VERSION. eg: +# PROJECT_NAME=jdk8u OR aarch64-port +# REPO_NAME=jdk8u60 OR jdk8u60 +# VERSION=jdk8u60-b27 OR aarch64-jdk8u65-b17 OR for head, keyword 'tip' should do the job there +# +# If you don't, default are used and so already uploaded tarball regenerated +# They are used to create correct name and are used in construction of sources url (unless REPO_ROOT is set) +# +# For other useful variables see generate_source_tarball.sh +# +# the used values are then substituted to spec and sources + +if [ ! "x$PR2126" = "x" ] ; then + if [ ! -f "$PR2126" ] ; then + echo "You have specified PR2126 as $PR2126 but it does not exists. exiting" + exit 1 + fi +fi + +set -e + +if [ "x$PROJECT_NAME" = "x" ] ; then + PROJECT_NAME="aarch64-port" +fi +if [ "x$REPO_NAME" = "x" ] ; then + REPO_NAME="jdk8u-shenandoah" +fi +if [ "x$VERSION" = "x" ] ; then + VERSION="aarch64-shenandoah-jdk8u262-b10" +fi + +if [ "x$COMPRESSION" = "x" ] ; then +# rhel 5 needs tar.gz + COMPRESSION=xz +fi +if [ "x$FILE_NAME_ROOT" = "x" ] ; then + FILE_NAME_ROOT=${PROJECT_NAME}-${REPO_NAME}-${VERSION} +fi +if [ "x$PKG" = "x" ] ; then + URL=`cat .git/config | grep url` + PKG=${URL##*/} +fi +if [ "x$SPEC" = "x" ] ; then + SPEC=${PKG}.spec +fi +if [ "x$RELEASE" = "x" ] ; then + RELEASE=1 +fi + +FILENAME=${FILE_NAME_ROOT}.tar.${COMPRESSION} + +if [ ! -f ${FILENAME} ] ; then +echo "Generating ${FILENAME}" +. ./generate_source_tarball.sh +else +echo "${FILENAME} already exists, using" +fi + + +echo "Touching spec: $SPEC" +echo sed -i "s/^%global\s\+project.*/%global project ${PROJECT_NAME}/" $SPEC +echo sed -i "s/^%global\s\+repo.*/%global repo ${REPO_NAME}/" $SPEC +echo sed -i "s/^%global\s\+revision.*/%global revision ${VERSION}/" $SPEC +# updated sources, resetting release +echo sed -i "s/^Release:.*/Release: $RELEASE.%{buildver}%{?dist}/" $SPEC + +echo "New sources" +cat sources +a_sources=`cat sources | sed "s/.*(//g" | sed "s/).*//g" | sed "s/.*\s\+//g"` +echo " you can get inspired by following %changelog template:" +user_name=`whoami` +user_record=$(getent passwd $user_name) +user_gecos_field=$(echo "$user_record" | cut -d ':' -f 5) +user_full_name=$(echo "$user_gecos_field" | cut -d ',' -f 1) +spec_date=`date +"%a %b %d %Y"` +# See spec: +revision_helper=`echo ${MAIN_VERSION%-*}` +updatever=`echo ${revision_helper##*u}` +buildver=`echo ${MAIN_VERSION##*-}` +echo "* $spec_date $user_full_name <$user_name@redhat.com> - 1:1.8.0.$updatever-$RELEASE.$buildver" +echo "- updated to $MAIN_VERSION (from $PROJECT_NAME/$MAIN_REPO_NAME)" +echo "- updated to $VERSION (from $PROJECT_NAME/$REPO_NAME) of hotspot" +echo "- used $FILENAME as new sources" +echo "- used $FILENAME_SH as new sources for hotspot" + +echo " execute:" +echo "fedpkg/rhpkg new-sources "$a_sources +echo " to upload sources" +echo "you can verify by fedpkg/rhpkg prep --arch XXXX on all architectures: x86_64 i386 i586 i686 ppc ppc64 ppc64le s390 s390x aarch64 armv7hl" +