1 /*
2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 8046516
27  * @summary Segmentation fault in JVM (easily reproducible)
28  *
29  * @run main/othervm -XX:-TieredCompilation -Xbatch compiler.loopopts.TestLogSum
30  * @author jackkamm@gmail.com
31  */
32 
33 package compiler.loopopts;
34 
35 import java.util.Arrays;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39 
40 public class TestLogSum {
main(String[] args)41   public static void main(String[] args) {
42     double sum;
43 
44     for (int i = 0; i < 6; i++) {
45         for (int n = 2; n < 30; n++) {
46            for (int j = 1; j <= n; j++) {
47               for (int k = 1; k <= j; k++) {
48                 // System.out.println(computeSum(k, j));
49                 sum = computeSum(k, j);
50               }
51            }
52         }
53       }
54    }
55 
56    private static Map<List<Integer>, Double> cache = new HashMap<List<Integer>, Double>();
computeSum(int x, int y)57    public static double computeSum(int x, int y) {
58       List<Integer> key = Arrays.asList(new Integer[] {x, y});
59 
60       if (!cache.containsKey(key)) {
61 
62         // explicitly creating/updating a double[] array, instead of using the LogSumArray wrapper object, will prevent the error
63         LogSumArray toReturn = new LogSumArray(x);
64 
65         // changing loop indices will prevent the error
66         // in particular, for(z=0; z<x-1; z++), and then using z+1 in place of z, will not produce error
67         for (int z = 1; z < x+1; z++) {
68            double logSummand = Math.log(z + x + y);
69            toReturn.addLogSummand(logSummand);
70         }
71 
72         // returning the value here without cacheing it will prevent the segfault
73         cache.put(key, toReturn.retrieveLogSum());
74       }
75       return cache.get(key);
76    }
77 
78    /*
79     * Given a bunch of logarithms log(X),log(Y),log(Z),...
80     * This class is used to compute the log of the sum, log(X+Y+Z+...)
81     */
82    private static class LogSumArray {
83       private double[] logSummandArray;
84       private int currSize;
85 
86       private double maxLogSummand;
87 
LogSumArray(int maxEntries)88       public LogSumArray(int maxEntries) {
89         this.logSummandArray = new double[maxEntries];
90 
91         this.currSize = 0;
92         this.maxLogSummand = Double.NEGATIVE_INFINITY;
93       }
94 
addLogSummand(double logSummand)95       public void addLogSummand(double logSummand) {
96         logSummandArray[currSize] = logSummand;
97         currSize++;
98         // removing this line will prevent the error
99         maxLogSummand = Math.max(maxLogSummand, logSummand);
100       }
101 
retrieveLogSum()102       public double retrieveLogSum() {
103         if (maxLogSummand == Double.NEGATIVE_INFINITY) return Double.NEGATIVE_INFINITY;
104 
105         assert currSize <= logSummandArray.length;
106 
107         double factorSum = 0;
108         for (int i = 0; i < currSize; i++) {
109            factorSum += Math.exp(logSummandArray[i] - maxLogSummand);
110         }
111 
112         return Math.log(factorSum) + maxLogSummand;
113       }
114    }
115 }
116