src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java
changeset 54669 ad45b3802d4e
child 58793 81ad1da857f6
equal deleted inserted replaced
54668:0bda2308eded 54669:ad45b3802d4e
       
     1 /*
       
     2  * Copyright (c) 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 java.io.ByteArrayOutputStream;
       
    26 import java.io.DataOutputStream;
       
    27 import java.io.IOException;
       
    28 import java.security.MessageDigest;
       
    29 import java.security.NoSuchAlgorithmException;
       
    30 import java.util.Arrays;
       
    31 
       
    32 import jdk.vm.ci.common.JVMCIError;
       
    33 import jdk.vm.ci.meta.ResolvedJavaMethod;
       
    34 import jdk.vm.ci.meta.ResolvedJavaType;
       
    35 import jdk.vm.ci.meta.SpeculationLog.SpeculationReasonEncoding;
       
    36 
       
    37 /**
       
    38  * Implements a {@link SpeculationReasonEncoding} that {@linkplain #getByteArray() produces} a byte
       
    39  * array. Data is added via a {@link DataOutputStream}. When producing the final byte array, if the
       
    40  * total length of data exceeds the length of a SHA-1 digest, then a SHA-1 digest of the data is
       
    41  * produced instead.
       
    42  */
       
    43 final class HotSpotSpeculationEncoding extends ByteArrayOutputStream implements SpeculationReasonEncoding {
       
    44 
       
    45     private DataOutputStream dos = new DataOutputStream(this);
       
    46     private byte[] result;
       
    47 
       
    48     HotSpotSpeculationEncoding() {
       
    49         super(SHA1_LENGTH);
       
    50     }
       
    51 
       
    52     private void checkOpen() {
       
    53         if (result != null) {
       
    54             throw new IllegalArgumentException("Cannot update closed speculation encoding");
       
    55         }
       
    56     }
       
    57 
       
    58     private static final int NULL_METHOD = -1;
       
    59     private static final int NULL_TYPE = -2;
       
    60     private static final int NULL_STRING = -3;
       
    61 
       
    62     @Override
       
    63     public void addByte(int value) {
       
    64         checkOpen();
       
    65         try {
       
    66             dos.writeByte(value);
       
    67         } catch (IOException e) {
       
    68             throw new InternalError(e);
       
    69         }
       
    70     }
       
    71 
       
    72     @Override
       
    73     public void addShort(int value) {
       
    74         checkOpen();
       
    75         try {
       
    76             dos.writeShort(value);
       
    77         } catch (IOException e) {
       
    78             throw new InternalError(e);
       
    79         }
       
    80     }
       
    81 
       
    82     @Override
       
    83     public void addMethod(ResolvedJavaMethod method) {
       
    84         if (!addNull(method, NULL_METHOD)) {
       
    85             checkOpen();
       
    86             if (method instanceof HotSpotResolvedJavaMethodImpl) {
       
    87                 try {
       
    88                     dos.writeLong(((HotSpotResolvedJavaMethodImpl) method).getMetaspaceMethod());
       
    89                 } catch (IOException e) {
       
    90                     throw new InternalError(e);
       
    91                 }
       
    92             } else {
       
    93                 throw new IllegalArgumentException("Cannot encode unsupported type " + method.getClass().getName() + ": " + method.format("%H.%n(%p)"));
       
    94             }
       
    95         }
       
    96     }
       
    97 
       
    98     @Override
       
    99     public void addType(ResolvedJavaType type) {
       
   100         if (!addNull(type, NULL_TYPE)) {
       
   101             checkOpen();
       
   102             if (type instanceof HotSpotResolvedObjectTypeImpl) {
       
   103                 try {
       
   104                     dos.writeLong(((HotSpotResolvedObjectTypeImpl) type).getMetaspaceKlass());
       
   105                 } catch (IOException e) {
       
   106                     throw new InternalError(e);
       
   107                 }
       
   108             } else {
       
   109                 throw new IllegalArgumentException("Cannot encode unsupported type " + type.getClass().getName() + ": " + type.toClassName());
       
   110             }
       
   111         }
       
   112     }
       
   113 
       
   114     @Override
       
   115     public void addString(String value) {
       
   116         if (!addNull(value, NULL_STRING)) {
       
   117             checkOpen();
       
   118             try {
       
   119                 dos.writeChars(value);
       
   120             } catch (IOException e) {
       
   121                 throw new InternalError(e);
       
   122             }
       
   123         }
       
   124     }
       
   125 
       
   126     @Override
       
   127     public void addInt(int value) {
       
   128         checkOpen();
       
   129         try {
       
   130             dos.writeInt(value);
       
   131         } catch (IOException e) {
       
   132             throw new InternalError(e);
       
   133         }
       
   134     }
       
   135 
       
   136     @Override
       
   137     public void addLong(long value) {
       
   138         checkOpen();
       
   139         try {
       
   140             dos.writeLong(value);
       
   141         } catch (IOException e) {
       
   142             throw new InternalError(e);
       
   143         }
       
   144     }
       
   145 
       
   146     private boolean addNull(Object o, int nullValue) {
       
   147         if (o == null) {
       
   148             addInt(nullValue);
       
   149             return true;
       
   150         }
       
   151         return false;
       
   152     }
       
   153 
       
   154     /**
       
   155      * Prototype SHA1 digest that is cloned before use.
       
   156      */
       
   157     private static final MessageDigest SHA1 = getSHA1();
       
   158     private static final int SHA1_LENGTH = SHA1.getDigestLength();
       
   159 
       
   160     private static MessageDigest getSHA1() {
       
   161         try {
       
   162             MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
       
   163             sha1.clone();
       
   164             return sha1;
       
   165         } catch (CloneNotSupportedException | NoSuchAlgorithmException e) {
       
   166             // Should never happen given that SHA-1 is mandated in a
       
   167             // compliant Java platform implementation.
       
   168             throw new JVMCIError("Expect a cloneable implementation of a SHA-1 message digest to be available", e);
       
   169         }
       
   170     }
       
   171 
       
   172     /**
       
   173      * Gets the final encoded byte array and closes this encoding such that any further attempts to
       
   174      * update it result in an {@link IllegalArgumentException}.
       
   175      */
       
   176     byte[] getByteArray() {
       
   177         if (result == null) {
       
   178             if (count > SHA1_LENGTH) {
       
   179                 try {
       
   180                     MessageDigest md = (MessageDigest) SHA1.clone();
       
   181                     md.update(buf, 0, count);
       
   182                     result = md.digest();
       
   183                 } catch (CloneNotSupportedException e) {
       
   184                     throw new InternalError(e);
       
   185                 }
       
   186             } else {
       
   187                 if (buf.length == count) {
       
   188                     // No need to copy the byte array
       
   189                     return buf;
       
   190                 }
       
   191                 result = Arrays.copyOf(buf, count);
       
   192             }
       
   193             dos = null;
       
   194         }
       
   195         return result;
       
   196     }
       
   197 }