1 /*
   2  * Copyright (c) 2017, 2018, 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 package org.graalvm.compiler.replacements.amd64;
  26 
  27 import org.graalvm.compiler.api.replacements.ClassSubstitution;
  28 import org.graalvm.compiler.api.replacements.Fold;
  29 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
  30 import org.graalvm.compiler.api.replacements.MethodSubstitution;
  31 import org.graalvm.compiler.nodes.DeoptimizeNode;
  32 import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode;
  33 import org.graalvm.compiler.word.Word;
  34 import jdk.internal.vm.compiler.word.Pointer;
  35 
  36 import jdk.vm.ci.meta.DeoptimizationAction;
  37 import jdk.vm.ci.meta.DeoptimizationReason;
  38 import jdk.vm.ci.meta.JavaKind;
  39 import jdk.vm.ci.meta.MetaAccessProvider;
  40 
  41 // JaCoCo Exclude
  42 
  43 /**
  44  * Substitutions for {@code java.lang.StringUTF16} methods.
  45  *
  46  * Since JDK 9.
  47  */
  48 @ClassSubstitution(className = "java.lang.StringUTF16", optional = true)
  49 public class AMD64StringUTF16Substitutions {
  50 
  51     @Fold
  52     static int byteArrayBaseOffset(@InjectedParameter MetaAccessProvider metaAccess) {
  53         return metaAccess.getArrayBaseOffset(JavaKind.Byte);
  54     }
  55 
  56     @Fold
  57     static int byteArrayIndexScale(@InjectedParameter MetaAccessProvider metaAccess) {
  58         return metaAccess.getArrayIndexScale(JavaKind.Byte);
  59     }
  60 
  61     @Fold
  62     static int charArrayBaseOffset(@InjectedParameter MetaAccessProvider metaAccess) {
  63         return metaAccess.getArrayBaseOffset(JavaKind.Char);
  64     }
  65 
  66     @Fold
  67     static int charArrayIndexScale(@InjectedParameter MetaAccessProvider metaAccess) {
  68         return metaAccess.getArrayIndexScale(JavaKind.Char);
  69     }
  70 
  71     /** Marker value for the {@link InjectedParameter} injected parameter. */
  72     static final MetaAccessProvider INJECTED = null;
  73 
  74     /**
  75      * @param value is char[]
  76      * @param other is char[]
  77      */
  78     @MethodSubstitution
  79     public static int compareTo(byte[] value, byte[] other) {
  80         return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Char, JavaKind.Char);
  81     }
  82 
  83     /**
  84      * @param value is char[]
  85      * @param other is byte[]
  86      */
  87     @MethodSubstitution
  88     public static int compareToLatin1(byte[] value, byte[] other) {
  89         /*
  90          * Swapping array arguments because intrinsic expects order to be byte[]/char[] but kind
  91          * arguments stay in original order.
  92          */
  93         return ArrayCompareToNode.compareTo(other, value, other.length, value.length, JavaKind.Char, JavaKind.Byte);
  94     }
  95 
  96     @MethodSubstitution(optional = true)
  97     public static int indexOfCharUnsafe(byte[] value, int ch, int fromIndex, int max) {
  98         Pointer sourcePointer = Word.objectToTrackedPointer(value).add(byteArrayBaseOffset(INJECTED)).add(fromIndex * charArrayIndexScale(INJECTED));
  99         int result = AMD64ArrayIndexOf.indexOf1Char(sourcePointer, max - fromIndex, (char) ch);
 100         if (result != -1) {
 101             return result + fromIndex;
 102         }
 103         return result;
 104     }
 105 
 106     /**
 107      * Intrinsic for {@code java.lang.StringUTF16.compress([CI[BII)I}.
 108      *
 109      * <pre>
 110      * @HotSpotIntrinsicCandidate
 111      * public static int compress(char[] src, int src_indx, byte[] dst, int dst_indx, int len)
 112      * </pre>
 113      */
 114     @MethodSubstitution
 115     public static int compress(char[] src, int srcIndex, byte[] dest, int destIndex, int len) {
 116         if (len < 0 || srcIndex < 0 || (srcIndex + len > src.length) || destIndex < 0 || (destIndex + len > dest.length)) {
 117             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException);
 118         }
 119 
 120         Pointer srcPointer = Word.objectToTrackedPointer(src).add(charArrayBaseOffset(INJECTED)).add(srcIndex * charArrayIndexScale(INJECTED));
 121         Pointer destPointer = Word.objectToTrackedPointer(dest).add(byteArrayBaseOffset(INJECTED)).add(destIndex * byteArrayIndexScale(INJECTED));
 122         return AMD64StringUTF16CompressNode.compress(srcPointer, destPointer, len, JavaKind.Char);
 123     }
 124 
 125     /**
 126      * Intrinsic for {@code }java.lang.StringUTF16.compress([BI[BII)I}.
 127      *
 128      * <pre>
 129      * @HotSpotIntrinsicCandidate
 130      * public static int compress(byte[] src, int src_indx, byte[] dst, int dst_indx, int len)
 131      * </pre>
 132      *
 133      * In this variant {@code dest} refers to a byte array containing 2 byte per char so
 134      * {@code srcIndex} and {@code len} are in terms of char elements and have to be scaled by 2
 135      * when referring to {@code src}.
 136      */
 137     @MethodSubstitution
 138     public static int compress(byte[] src, int srcIndex, byte[] dest, int destIndex, int len) {
 139         if (len < 0 || srcIndex < 0 || (srcIndex * 2 + len * 2 > src.length) || destIndex < 0 || (destIndex + len > dest.length)) {
 140             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException);
 141         }
 142 
 143         Pointer srcPointer = Word.objectToTrackedPointer(src).add(byteArrayBaseOffset(INJECTED)).add(srcIndex * 2 * byteArrayIndexScale(INJECTED));
 144         Pointer destPointer = Word.objectToTrackedPointer(dest).add(byteArrayBaseOffset(INJECTED)).add(destIndex * byteArrayIndexScale(INJECTED));
 145         return AMD64StringUTF16CompressNode.compress(srcPointer, destPointer, len, JavaKind.Byte);
 146     }
 147 
 148 }