src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java
Index Unified diffs Context diffs Sdiffs Frames Patch New Old Previous File Next File open Sdiff src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot

src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java

Print this page


   1 /*
   2  * Copyright (c) 2014, 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 package jdk.vm.ci.hotspot;
  24 
  25 import java.util.HashMap;
  26 import java.util.HashSet;
  27 import java.util.Map;
  28 import java.util.Set;
  29 






  30 import jdk.vm.ci.meta.JavaConstant;
  31 import jdk.vm.ci.meta.SpeculationLog;
  32 












  33 public class HotSpotSpeculationLog implements SpeculationLog {






































































  34     public static final class HotSpotSpeculation extends Speculation {
  35         private JavaConstant encoding;
  36 
  37         HotSpotSpeculation(SpeculationReason reason, JavaConstant encoding) {










  38             super(reason);

  39             this.encoding = encoding;
  40         }
  41 
  42         public JavaConstant getEncoding() {
  43             return encoding;








  44         }
  45     }
  46 
  47     /** Written by the C++ code that performs deoptimization. */
  48     private volatile long lastFailed;




  49 
  50     /** All speculations that have caused a deoptimization. */
  51     private Set<SpeculationReason> failedSpeculations;
  52 
  53     /** Strong references to all reasons embedded in the current nmethod. */
  54     private HashMap<SpeculationReason, JavaConstant> speculations;



  55 
  56     private long currentSpeculationID;




  57 
  58     @Override
  59     public synchronized void collectFailedSpeculations() {
  60         if (lastFailed != 0) {
  61             if (failedSpeculations == null) {
  62                 failedSpeculations = new HashSet<>(2);
  63             }
  64             if (speculations != null) {
  65                 SpeculationReason lastFailedSpeculation = lookupSpeculation(this.lastFailed);
  66                 if (lastFailedSpeculation != null) {
  67                     failedSpeculations.add(lastFailedSpeculation);
  68                 }
  69                 lastFailed = 0;
  70                 speculations = null;












  71             }
  72         }
  73     }
  74 
  75     private SpeculationReason lookupSpeculation(long value) {
  76         for (Map.Entry<SpeculationReason, JavaConstant> entry : speculations.entrySet()) {
  77             if (value == entry.getValue().asLong()) {
  78                 return entry.getKey();
  79             }



  80         }
  81         return null;






  82     }
  83 
  84     @Override
  85     public synchronized boolean maySpeculate(SpeculationReason reason) {
  86         if (failedSpeculations != null && failedSpeculations.contains(reason)) {
  87             return false;






  88         }









  89         return true;
  90     }















  91 
  92     @Override
  93     public synchronized Speculation speculate(SpeculationReason reason) {


  94         if (speculations == null) {
  95             speculations = new HashMap<>();













  96         }
  97         JavaConstant id = speculations.get(reason);
  98         if (id == null) {
  99             id = JavaConstant.forLong(++currentSpeculationID);
 100             speculations.put(reason, id);

 101         }
 102         return new HotSpotSpeculation(reason, id);











 103     }
 104 
 105     @Override
 106     public synchronized boolean hasSpeculations() {
 107         return speculations != null && !speculations.isEmpty();
 108     }
 109 
 110     @Override
 111     public synchronized Speculation lookupSpeculation(JavaConstant constant) {
 112         if (constant.isDefaultForKind()) {
 113             return NO_SPECULATION;
 114         }
 115         SpeculationReason reason = lookupSpeculation(constant.asLong());
 116         assert reason != null : "Speculation should have been registered";
 117         return new HotSpotSpeculation(reason, constant);




























































 118     }
 119 }

   1 /*
   2  * Copyright (c) 2014, 2019, 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 package jdk.vm.ci.hotspot;
  24 
  25 import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;



  26 
  27 import java.util.ArrayList;
  28 import java.util.Arrays;
  29 import java.util.Formatter;
  30 import java.util.List;
  31 
  32 import jdk.vm.ci.code.BailoutException;
  33 import jdk.vm.ci.meta.JavaConstant;
  34 import jdk.vm.ci.meta.SpeculationLog;
  35 
  36 /**
  37  * Implements a {@link SpeculationLog} that can be used to:
  38  * <ul>
  39  * <li>Query failed speculations recorded in a native linked list of {@code FailedSpeculation}s (see
  40  * methodData.hpp).</li>
  41  * <li>Make speculations during compilation and record them in compiled code. This must only be done
  42  * on compilation-local {@link HotSpotSpeculationLog} objects.</li>
  43  * </ul>
  44  *
  45  * The choice of constructor determines whether the native failed speculations list is
  46  * {@linkplain #managesFailedSpeculations() managed} by a {@link HotSpotSpeculationLog} object.
  47  */
  48 public class HotSpotSpeculationLog implements SpeculationLog {
  49 
  50     private static final byte[] NO_FLATTENED_SPECULATIONS = {};
  51 
  52     /**
  53      * Creates a speculation log that manages a failed speculation list. That is, when this object
  54      * dies, the native resources of the list are freed.
  55      *
  56      * @see #managesFailedSpeculations()
  57      * @see #getFailedSpeculationsAddress()
  58      */
  59     public HotSpotSpeculationLog() {
  60         managesFailedSpeculations = true;
  61     }
  62 
  63     /**
  64      * Creates a speculation log that reads from an externally managed failed speculation list. That
  65      * is, the lifetime of the list is independent of this object.
  66      *
  67      * @param failedSpeculationsAddress an address in native memory at which the pointer to the
  68      *            externally managed sailed speculation list resides
  69      */
  70     public HotSpotSpeculationLog(long failedSpeculationsAddress) {
  71         if (failedSpeculationsAddress == 0) {
  72             throw new IllegalArgumentException("failedSpeculationsAddress cannot be 0");
  73         }
  74         this.failedSpeculationsAddress = failedSpeculationsAddress;
  75         managesFailedSpeculations = false;
  76     }
  77 
  78     /**
  79      * Gets the address of the pointer to the native failed speculations list.
  80      *
  81      * @see #managesFailedSpeculations()
  82      */
  83     public long getFailedSpeculationsAddress() {
  84         if (managesFailedSpeculations) {
  85             synchronized (this) {
  86                 if (failedSpeculationsAddress == 0L) {
  87                     failedSpeculationsAddress = UnsafeAccess.UNSAFE.allocateMemory(HotSpotJVMCIRuntime.getHostWordKind().getByteCount());
  88                     UnsafeAccess.UNSAFE.putAddress(failedSpeculationsAddress, 0L);
  89                     LogCleaner c = new LogCleaner(this, failedSpeculationsAddress);
  90                     assert c.address == failedSpeculationsAddress;
  91                 }
  92             }
  93         }
  94         return failedSpeculationsAddress;
  95     }
  96 
  97     /**
  98      * Adds {@code speculation} to the native list of failed speculations. To update this object's
  99      * view of the failed speculations, {@link #collectFailedSpeculations()} must be called after
 100      * this method returns.
 101      *
 102      * This method exists primarily for testing purposes. Speculations are normally only added to
 103      * the list by HotSpot during deoptimization.
 104      *
 105      * @return {@code false} if the speculation could not be appended to the list
 106      */
 107     public boolean addFailedSpeculation(Speculation speculation) {
 108         return compilerToVM().addFailedSpeculation(getFailedSpeculationsAddress(), ((HotSpotSpeculation) speculation).encoding);
 109     }
 110 
 111     /**
 112      * Returns {@code true} if the value returned by {@link #getFailedSpeculationsAddress()} is only
 113      * valid only as long as this object is alive, {@code false} otherwise.
 114      */
 115     public boolean managesFailedSpeculations() {
 116         return managesFailedSpeculations;
 117     }
 118 
 119     public static final class HotSpotSpeculation extends Speculation {

 120 
 121         /**
 122          * A speculation id is a long encoding an offset (high 32 bits) and a length (low 32 bts).
 123          * Combined, the index and length denote where the {@linkplain #encoding encoded
 124          * speculation} is in a {@linkplain HotSpotSpeculationLog#getFlattenedSpeculations
 125          * flattened} speculations array.
 126          */
 127         private final JavaConstant id;
 128 
 129         private final byte[] encoding;
 130 
 131         HotSpotSpeculation(SpeculationReason reason, JavaConstant id, byte[] encoding) {
 132             super(reason);
 133             this.id = id;
 134             this.encoding = encoding;
 135         }
 136 
 137         public JavaConstant getEncoding() {
 138             return id;
 139         }
 140 
 141         @Override
 142         public String toString() {
 143             long indexAndLength = id.asLong();
 144             int index = decodeIndex(indexAndLength);
 145             int length = decodeLength(indexAndLength);
 146             return String.format("{0x%016x[index: %d, len: %d, hash: 0x%x]: %s}", indexAndLength, index, length, Arrays.hashCode(encoding), getReason());
 147         }
 148     }
 149 
 150     /**
 151      * Address of a pointer to a set of failed speculations. The address is recorded in the nmethod
 152      * compiled with this speculation log such that when it fails a speculation, the speculation is
 153      * added to the list.
 154      */
 155     private long failedSpeculationsAddress;
 156 
 157     private final boolean managesFailedSpeculations;

 158 
 159     /**
 160      * The list of failed speculations read from native memory via
 161      * {@link CompilerToVM#getFailedSpeculations}.
 162      */
 163     private byte[][] failedSpeculations;
 164 
 165     /**
 166      * Speculations made during the compilation associated with this log.
 167      */
 168     private List<byte[]> speculations;
 169     private List<SpeculationReason> speculationReasons;
 170 
 171     @Override
 172     public void collectFailedSpeculations() {
 173         if (failedSpeculationsAddress != 0 && UnsafeAccess.UNSAFE.getLong(failedSpeculationsAddress) != 0) {
 174             failedSpeculations = compilerToVM().getFailedSpeculations(failedSpeculationsAddress, failedSpeculations);
 175             assert failedSpeculations.getClass() == byte[][].class;
 176         }




 177     }
 178 
 179     byte[] getFlattenedSpeculations(boolean validate) {
 180         if (speculations == null) {
 181             return NO_FLATTENED_SPECULATIONS;
 182         }
 183         if (validate) {
 184             int newFailuresStart = failedSpeculations == null ? 0 : failedSpeculations.length;
 185             collectFailedSpeculations();
 186             if (failedSpeculations != null && failedSpeculations.length != newFailuresStart) {
 187                 for (SpeculationReason reason : speculationReasons) {
 188                     byte[] encoding = encode(reason);
 189                     // Only check against new failures
 190                     if (contains(failedSpeculations, newFailuresStart, encoding)) {
 191                         throw new BailoutException(false, "Speculation failed: " + reason);
 192                     }
 193                 }
 194             }





 195         }
 196         int size = 0;
 197         for (byte[] s : speculations) {
 198             size += s.length;
 199         }
 200         byte[] result = new byte[size];
 201         size = 0;
 202         for (byte[] s : speculations) {
 203             System.arraycopy(s, 0, result, size, s.length);
 204             size += s.length;
 205         }
 206         return result;
 207     }
 208 
 209     @Override
 210     public boolean maySpeculate(SpeculationReason reason) {
 211         if (failedSpeculations == null) {
 212             collectFailedSpeculations();
 213         }
 214         if (failedSpeculations != null && failedSpeculations.length != 0) {
 215             byte[] encoding = encode(reason);
 216             return !contains(failedSpeculations, 0, encoding);
 217         }
 218         return true;
 219     }
 220 
 221     /**
 222      * @return {@code true} if {@code needle} is in {@code haystack[fromIndex..haystack.length-1]}
 223      */
 224     private static boolean contains(byte[][] haystack, int fromIndex, byte[] needle) {
 225         for (int i = fromIndex; i < haystack.length; i++) {
 226             byte[] fs = haystack[i];
 227 
 228             if (Arrays.equals(fs, needle)) {
 229                 return true;
 230             }
 231         }
 232         return false;
 233     }
 234 
 235     private static long encodeIndexAndLength(int index, int length) {
 236         return ((long) index) << 32 | length;
 237     }
 238 
 239     private static int decodeIndex(long indexAndLength) {
 240         return (int) (indexAndLength >>> 32);
 241     }
 242 
 243     private static int decodeLength(long indexAndLength) {
 244         return (int) indexAndLength & 0xFFFFFFFF;
 245     }
 246 
 247     @Override
 248     public Speculation speculate(SpeculationReason reason) {
 249         byte[] encoding = encode(reason);
 250         JavaConstant id;
 251         if (speculations == null) {
 252             speculations = new ArrayList<>();
 253             speculationReasons = new ArrayList<>();
 254             id = JavaConstant.forLong(encodeIndexAndLength(0, encoding.length));
 255             speculations.add(encoding);
 256             speculationReasons.add(reason);
 257         } else {
 258             id = null;
 259             int flattenedIndex = 0;
 260             for (byte[] fs : speculations) {
 261                 if (Arrays.equals(fs, encoding)) {
 262                     id = JavaConstant.forLong(encodeIndexAndLength(flattenedIndex, fs.length));
 263                     break;
 264                 }
 265                 flattenedIndex += fs.length;
 266             }

 267             if (id == null) {
 268                 id = JavaConstant.forLong(encodeIndexAndLength(flattenedIndex, encoding.length));
 269                 speculations.add(encoding);
 270                 speculationReasons.add(reason);
 271             }
 272         }
 273 
 274         return new HotSpotSpeculation(reason, id, encoding);
 275     }
 276 
 277     private static byte[] encode(SpeculationReason reason) {
 278         HotSpotSpeculationEncoding encoding = (HotSpotSpeculationEncoding) reason.encode(HotSpotSpeculationEncoding::new);
 279         byte[] result = encoding == null ? null : encoding.getByteArray();
 280         if (result == null) {
 281             throw new IllegalArgumentException(HotSpotSpeculationLog.class.getName() + " expects " + reason.getClass().getName() + ".encode() to return a non-empty encoding");
 282         }
 283         return result;
 284     }
 285 
 286     @Override
 287     public boolean hasSpeculations() {
 288         return speculations != null;
 289     }
 290 
 291     @Override
 292     public Speculation lookupSpeculation(JavaConstant constant) {
 293         if (constant.isDefaultForKind()) {
 294             return NO_SPECULATION;
 295         }
 296         int flattenedIndex = decodeIndex(constant.asLong());
 297         int index = 0;
 298         for (byte[] s : speculations) {
 299             if (flattenedIndex == 0) {
 300                 SpeculationReason reason = speculationReasons.get(index);
 301                 return new HotSpotSpeculation(reason, constant, s);
 302             }
 303             index++;
 304             flattenedIndex -= s.length;
 305         }
 306         throw new IllegalArgumentException("Unknown encoded speculation: " + constant);
 307     }
 308 
 309     @Override
 310     public String toString() {
 311         Formatter buf = new Formatter();
 312         buf.format("{managed:%s, failedSpeculationsAddress:0x%x, failedSpeculations:[", managesFailedSpeculations, failedSpeculationsAddress);
 313 
 314         String sep = "";
 315         if (failedSpeculations != null) {
 316             for (int i = 0; i < failedSpeculations.length; i++) {
 317                 buf.format("%s{len:%d, hash:0x%x}", sep, failedSpeculations[i].length, Arrays.hashCode(failedSpeculations[i]));
 318                 sep = ", ";
 319             }
 320         }
 321 
 322         buf.format("], speculations:[");
 323 
 324         int size = 0;
 325         if (speculations != null) {
 326             sep = "";
 327             for (int i = 0; i < speculations.size(); i++) {
 328                 byte[] s = speculations.get(i);
 329                 size += s.length;
 330                 buf.format("%s{len:%d, hash:0x%x, reason:{%s}}", sep, s.length, Arrays.hashCode(s), speculationReasons.get(i));
 331                 sep = ", ";
 332             }
 333         }
 334         buf.format("], len:%d, hash:0x%x}", size, Arrays.hashCode(getFlattenedSpeculations(false)));
 335         return buf.toString();
 336     }
 337 
 338     /**
 339      * Frees the native memory resources associated with {@link HotSpotSpeculationLog}s once they
 340      * become reclaimable.
 341      */
 342     private static final class LogCleaner extends Cleaner {
 343 
 344         LogCleaner(HotSpotSpeculationLog referent, long address) {
 345             super(referent);
 346             this.address = address;
 347         }
 348 
 349         @Override
 350         void doCleanup() {
 351             long pointer = UnsafeAccess.UNSAFE.getAddress(address);
 352             if (pointer != 0) {
 353                 compilerToVM().releaseFailedSpeculations(address);
 354             }
 355             UnsafeAccess.UNSAFE.freeMemory(address);
 356         }
 357 
 358         final long address;
 359     }
 360 }
 361 
src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java
Index Unified diffs Context diffs Sdiffs Frames Patch New Old Previous File Next File