Path: blob/master/jcl/src/java.base/share/classes/com/ibm/jit/JITHelpers.java
12628 views
/*[INCLUDE-IF Sidecar17]*/12package com.ibm.jit;34/*******************************************************************************5* Copyright (c) 1998, 2021 IBM Corp. and others6*7* This program and the accompanying materials are made available under8* the terms of the Eclipse Public License 2.0 which accompanies this9* distribution and is available at https://www.eclipse.org/legal/epl-2.0/10* or the Apache License, Version 2.0 which accompanies this distribution and11* is available at https://www.apache.org/licenses/LICENSE-2.0.12*13* This Source Code may also be made available under the following14* Secondary Licenses when the conditions for such availability set15* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU16* General Public License, version 2 with the GNU Classpath17* Exception [1] and GNU General Public License, version 2 with the18* OpenJDK Assembly Exception [2].19*20* [1] https://www.gnu.org/software/classpath/license.html21* [2] http://openjdk.java.net/legal/assembly-exception.html22*23* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception24*******************************************************************************/2526import com.ibm.oti.vm.J9UnmodifiableClass;27import java.lang.reflect.Field;28import java.lang.reflect.Array;29import com.ibm.oti.vm.VM;30/*[IF Sidecar19-SE]31import jdk.internal.misc.Unsafe;32import jdk.internal.reflect.Reflection;33import jdk.internal.reflect.CallerSensitive;34/*[ELSE]*/35import sun.misc.Unsafe;36import sun.reflect.Reflection;37import sun.reflect.CallerSensitive;38/*[ENDIF]*/3940/**41* The <code>JITHelpers</code> class contains methods used by the JIT to optimize certain primitive operations.42*/43@SuppressWarnings("javadoc")44@J9UnmodifiableClass45public final class JITHelpers {4647private static final JITHelpers helpers;48private static final Unsafe unsafe;4950private JITHelpers() {51}5253@CallerSensitive54public static JITHelpers getHelpers() {55if (Reflection.getCallerClass().getClassLoader() != null) {56throw new SecurityException("JITHelpers"); //$NON-NLS-1$57}58return helpers;59}6061/*62* Private method to provide access to the JITHelpers instance from jitted code without the stackwalk.63*/64private static JITHelpers jitHelpers() {65return helpers;66}6768public native int transformedEncodeUTF16Big(long src, long dest, int num);6970public native int transformedEncodeUTF16Little(long src, long dest, int num);7172/*73* Constants for getSuperclass.74*/75private static final int CLASS_IS_INTERFACE_OR_PRIMITIVE = classIsInterfaceFlag() | VM.J9_ACC_CLASS_INTERNAL_PRIMITIVE_TYPE;76private static final long JLCLASS_J9CLASS_OFFSET = javaLangClassJ9ClassOffset();77private static final int POINTER_SIZE = VM.ADDRESS_SIZE;78private static final boolean IS_32_BIT = (POINTER_SIZE == 4);7980public static final boolean IS_BIG_ENDIAN = isBigEndian();8182/*83* The following natives are used by the static initializer. They do not require special treatment by the JIT.84*/85private static native int javaLangClassJ9ClassOffset();8687private static int classIsInterfaceFlag() {88/* JVMS Table 4.8 ACC_INTERFACE=0x200 */89return 0x200;90}9192static {93helpers = new JITHelpers();94unsafe = Unsafe.getUnsafe();95}9697/**98* Java implementation of the native getSuperclass99*100* @param clazz101* The class to introspect (must not be null).102* @return The superclass, or null for primitive types, interfaces and java.lang.Object.103*/104public Class<?> getSuperclass(Class<?> clazz) {105if (IS_32_BIT) {106int j9Class = unsafe.getInt(clazz, JLCLASS_J9CLASS_OFFSET);107int romClass = unsafe.getInt(j9Class + VM.J9CLASS_ROMCLASS_OFFSET);108int modifiers = unsafe.getInt(romClass + VM.J9ROMCLASS_MODIFIERS_OFFSET);109if (0 == (modifiers & CLASS_IS_INTERFACE_OR_PRIMITIVE)) {110int superclasses = unsafe.getInt(j9Class + VM.J9CLASS_SUPERCLASSES_OFFSET);111int depthAndFlags = unsafe.getInt(j9Class + VM.J9CLASS_CLASS_DEPTH_AND_FLAGS_OFFSET);112int depth = (depthAndFlags & VM.J9_JAVA_CLASS_DEPTH_MASK);113if (depth > 0) {114int superclass = unsafe.getInt(superclasses + (POINTER_SIZE * (depth - 1)));115return getClassFromJ9Class32(superclass);116}117}118} else {119long j9Class = unsafe.getLong(clazz, JLCLASS_J9CLASS_OFFSET);120long romClass = unsafe.getLong(j9Class + VM.J9CLASS_ROMCLASS_OFFSET);121int modifiers = unsafe.getInt(romClass + VM.J9ROMCLASS_MODIFIERS_OFFSET);122if (0 == (modifiers & CLASS_IS_INTERFACE_OR_PRIMITIVE)) {123long superclasses = unsafe.getLong(j9Class + VM.J9CLASS_SUPERCLASSES_OFFSET);124long depthAndFlags = unsafe.getLong(j9Class + VM.J9CLASS_CLASS_DEPTH_AND_FLAGS_OFFSET);125long depth = (depthAndFlags & VM.J9_JAVA_CLASS_DEPTH_MASK);126if (depth > 0) {127long superclass = unsafe.getLong(superclasses + (POINTER_SIZE * (depth - 1)));128return getClassFromJ9Class64(superclass);129}130}131}132return null;133}134135/*136* To be recognized by the JIT and turned into trees that is foldable when obj is known at compile time.137*/138public boolean isArray(Object obj) {139if (is32Bit()) {140int j9Class = getJ9ClassFromObject32(obj);141int flags = getClassDepthAndFlagsFromJ9Class32(j9Class);142return (flags & VM.J9_ACC_CLASS_ARRAY) != 0;143}144else {145long j9Class = getJ9ClassFromObject64(obj);146// Cast the flag to int because only the lower 32 bits are valid and VM.J9_ACC_CLASS_ARRAY is int type147int flags = (int)getClassDepthAndFlagsFromJ9Class64(j9Class);148return (flags & VM.J9_ACC_CLASS_ARRAY) != 0;149}150}151152/*153* To be recognized by the JIT and turned into a load with vft symbol.154*/155public long getJ9ClassFromObject64(Object obj) {156Class<?> clazz = obj.getClass();157return getJ9ClassFromClass64(clazz);158}159160public int getJ9ClassFromObject32(Object obj) {161Class<?> clazz = obj.getClass();162return getJ9ClassFromClass32(clazz);163}164165166/*167* To be recognized by the JIT and returns true if the hardware supports SIMD case conversion.168*/169public boolean supportsIntrinsicCaseConversion() {170return false;171}172173/**174* To be used by the JIT when performing SIMD upper case conversion with Latin 1 strings.175* @param value the underlying array for the source string.176* @param output a new array which will be used for the converted string.177* @param length the number of bytes used to represent the string.178* @return True if intrinsic conversion was successful, false if fallback conversion must be used.179*/180public boolean toUpperIntrinsicLatin1(byte[] value, byte[] output, int length) {181return false;182}183184/**185* To be used by the JIT when performing SIMD lower case conversion with Latin 1 strings.186* @param value the underlying array for the source string.187* @param output a new array which will be used for the converted string.188* @param length the number of bytes used to represent the string.189* @return True if intrinsic conversion was successful, false if fallback conversion must be used.190*/191public boolean toLowerIntrinsicLatin1(byte[] value, byte[] output, int length) {192return false;193}194195/**196* To be used by the JIT when performing SIMD upper case conversion with UTF16 strings.197* @param value the underlying array for the source string.198* @param output a new array which will be used for the converted string.199* @param length the number of bytes used to represent the string.200* @return True if intrinsic conversion was successful, false if fallback conversion must be used.201*/202public boolean toUpperIntrinsicUTF16(byte[] value, byte[] output, int length) {203return false;204}205206/**207* To be used by the JIT when performing SIMD lower case conversion with UTF16 strings.208* @param value the underlying array for the source string.209* @param output a new array which will be used for the converted string.210* @param length the number of bytes used to represent the string.211* @return True if intrinsic conversion was successful, false if fallback conversion must be used.212*/213public boolean toLowerIntrinsicUTF16(byte[] value, byte[] output, int length) {214return false;215}216/**217* To be used by the JIT when performing SIMD upper case conversion with Latin 1 strings.218* @param value the underlying array for the source string.219* @param output a new array which will be used for the converted string.220* @param length the number of bytes used to represent the string.221* @return True if intrinsic conversion was successful, false if fallback conversion must be used.222*/223public boolean toUpperIntrinsicLatin1(char[] value, char[] output, int length) {224return false;225}226227/**228* To be used by the JIT when performing SIMD lower case conversion with Latin 1 strings.229* @param value the underlying array for the source string.230* @param output a new array which will be used for the converted string.231* @param length the number of bytes used to represent the string.232* @return True if intrinsic conversion was successful, false if fallback conversion must be used.233*/234public boolean toLowerIntrinsicLatin1(char[] value, char[] output, int length) {235return false;236}237238/**239* To be used by the JIT when performing SIMD upper case conversion with UTF16 strings.240* @param value the underlying array for the source string.241* @param output a new array which will be used for the converted string.242* @param length the number of bytes used to represent the string.243* @return True if intrinsic conversion was successful, false if fallback conversion must be used.244*/245public boolean toUpperIntrinsicUTF16(char[] value, char[] output, int length) {246return false;247}248249/**250* To be used by the JIT when performing SIMD lower case conversion with UTF16 strings.251* @param value the underlying array for the source string.252* @param output a new array which will be used for the converted string.253* @param length the number of bytes used to represent the string.254* @return True if intrinsic conversion was successful, false if fallback conversion must be used.255*/256public boolean toLowerIntrinsicUTF16(char[] value, char[] output, int length) {257return false;258}259260/*261* sun.misc.Unsafe.get* and put* have to generate internal control flow for correctness due to different object shapes. The JIT emitted sequences262* checks for and handles: 1) standard fields in normal objects 2) static fields from classes 3) entries from arrays This sequence is branchy and263* hard for us to optimize. The better solution in cases where we know the type of object is to use case specific accessors which are the methods264* below. Be careful that you know the type of the object you are getting from before using these.265*266* NOTE: JIT assumes that obj is non-null and offset is positive - breaking this assumption is just asking for trouble.267*/268public int getIntFromObject(Object obj, long offset) {269return unsafe.getInt(obj, offset);270}271272public int getIntFromObjectVolatile(Object obj, long offset) {273return unsafe.getIntVolatile(obj, offset);274}275276public long getLongFromObject(Object obj, long offset) {277return unsafe.getLong(obj, offset);278}279280public long getLongFromObjectVolatile(Object obj, long offset) {281return unsafe.getLongVolatile(obj, offset);282}283284public Object getObjectFromObject(Object obj, long offset) {285return unsafe.getObject(obj, offset);286}287288public Object getObjectFromObjectVolatile(Object obj, long offset) {289return unsafe.getObjectVolatile(obj, offset);290}291292public void putIntInObject(Object obj, long offset, int value) {293unsafe.putInt(obj, offset, value);294}295296public void putIntInObjectVolatile(Object obj, long offset, int value) {297unsafe.putIntVolatile(obj, offset, value);298}299300public void putLongInObject(Object obj, long offset, long value) {301unsafe.putLong(obj, offset, value);302}303304public void putLongInObjectVolatile(Object obj, long offset, long value) {305unsafe.putLongVolatile(obj, offset, value);306}307308public void putObjectInObject(Object obj, long offset, Object value) {309unsafe.putObject(obj, offset, value);310}311312public void putObjectInObjectVolatile(Object obj, long offset, Object value) {313unsafe.putObjectVolatile(obj, offset, value);314}315316public boolean compareAndSwapIntInObject(Object obj, long offset, int expected, int value) {317/*[IF Sidecar19-SE-OpenJ9]*/318return unsafe.compareAndSetInt(obj, offset, expected, value);319/*[ELSE]320return unsafe.compareAndSwapInt(obj, offset, expected, value);321/*[ENDIF]*/322}323324public boolean compareAndSwapLongInObject(Object obj, long offset, long expected, long value) {325/*[IF Sidecar19-SE-OpenJ9]*/326return unsafe.compareAndSetLong(obj, offset, expected, value);327/*[ELSE]328return unsafe.compareAndSwapLong(obj, offset, expected, value);329/*[ENDIF]*/330}331332public boolean compareAndSwapObjectInObject(Object obj, long offset, Object expected, Object value) {333/*[IF Sidecar19-SE-OpenJ9]*/334return unsafe.compareAndSetObject(obj, offset, expected, value);335/*[ELSE]336return unsafe.compareAndSwapObject(obj, offset, expected, value);337/*[ENDIF]*/338}339340public byte getByteFromArray(Object obj, long offset) {341return unsafe.getByte(obj, offset);342}343344public byte getByteFromArrayVolatile(Object obj, long offset) {345return unsafe.getByteVolatile(obj, offset);346}347348public char getCharFromArray(Object obj, long offset) {349return unsafe.getChar(obj, offset);350}351352public char getCharFromArrayVolatile(Object obj, long offset) {353return unsafe.getCharVolatile(obj, offset);354}355356public int getIntFromArray(Object obj, long offset) {357return unsafe.getInt(obj, offset);358}359360public int getIntFromArrayVolatile(Object obj, long offset) {361return unsafe.getIntVolatile(obj, offset);362}363364public long getLongFromArray(Object obj, long offset) {365return unsafe.getLong(obj, offset);366}367368public long getLongFromArrayVolatile(Object obj, long offset) {369return unsafe.getLongVolatile(obj, offset);370}371372public Object getObjectFromArray(Object obj, long offset) {373return unsafe.getObject(obj, offset);374}375376public Object getObjectFromArrayVolatile(Object obj, long offset) {377return unsafe.getObjectVolatile(obj, offset);378}379380public void putByteInArray(Object obj, long offset, byte value) {381unsafe.putByte(obj, offset, value);382}383384public void putByteInArrayVolatile(Object obj, long offset, byte value) {385unsafe.putByteVolatile(obj, offset, value);386}387388public void putCharInArray(Object obj, long offset, char value) {389unsafe.putChar(obj, offset, value);390}391392public void putCharInArrayVolatile(Object obj, long offset, char value) {393unsafe.putCharVolatile(obj, offset, value);394}395396public void putIntInArray(Object obj, long offset, int value) {397unsafe.putInt(obj, offset, value);398}399400public void putIntInArrayVolatile(Object obj, long offset, int value) {401unsafe.putIntVolatile(obj, offset, value);402}403404public void putLongInArray(Object obj, long offset, long value) {405unsafe.putLong(obj, offset, value);406}407408public void putLongInArrayVolatile(Object obj, long offset, long value) {409unsafe.putLongVolatile(obj, offset, value);410}411412public void putObjectInArray(Object obj, long offset, Object value) {413unsafe.putObject(obj, offset, value);414}415416public void putObjectInArrayVolatile(Object obj, long offset, Object value) {417unsafe.putObjectVolatile(obj, offset, value);418}419420public boolean compareAndSwapIntInArray(Object obj, long offset, int expected, int value) {421/*[IF Sidecar19-SE-OpenJ9]*/422return unsafe.compareAndSetInt(obj, offset, expected, value);423/*[ELSE]424return unsafe.compareAndSwapInt(obj, offset, expected, value);425/*[ENDIF]*/426}427428public boolean compareAndSwapLongInArray(Object obj, long offset, long expected, long value) {429/*[IF Sidecar19-SE-OpenJ9]*/430return unsafe.compareAndSetLong(obj, offset, expected, value);431/*[ELSE]432return unsafe.compareAndSwapLong(obj, offset, expected, value);433/*[ENDIF]*/434}435436public boolean compareAndSwapObjectInArray(Object obj, long offset, Object expected, Object value) {437/*[IF Sidecar19-SE-OpenJ9]*/438return unsafe.compareAndSetObject(obj, offset, expected, value);439/*[ELSE]440return unsafe.compareAndSwapObject(obj, offset, expected, value);441/*[ENDIF]*/442}443444public char byteToCharUnsigned(byte b) {445return (char) ((char) b & (char) 0x00ff);446}447448/**449* Determine whether {@code lhs} is at a lower address than {@code rhs}.450*451* Because objects can be moved by the garbage collector, the ordering of452* the addresses of distinct objects is not stable over time. As such, the453* result of this comparison should be used for heuristic purposes only.454*455* A null reference is considered less than any non-null reference.456*457* @param lhs The left hand side of the comparison458* @param rhs The right hand side of the comparison459* @return true if {@code lhs} is at a lower address, false otherwise460*/461public native boolean acmplt(Object lhs, Object rhs);462463private static long storeBits(long dest, int width, long value, int vwidth, int offset) {464int offsetToModify = IS_BIG_ENDIAN ? ((width - 1) - ((offset * vwidth) % width)) : ((offset * vwidth) % width);465466long vmask = (-1 >>> ((8 - vwidth) * 8));467long dmask = ~(vmask << (8 * offsetToModify));468469return (dest & dmask) | ((value & vmask) << (8 * offsetToModify));470}471472private static long readBits(long src, int width, int vwidth, int offset) {473int offsetToRead = IS_BIG_ENDIAN ? ((width - 1) - ((offset * vwidth) % width)) : ((offset * vwidth) % width);474475long vmask = (-1 >>> ((8 - vwidth) * 8));476long smask = vmask << (8 * offsetToRead);477478return (src & smask) >>> (8 * offsetToRead);479}480481public void putByteInArrayByIndex(Object obj, int index, byte value) {482Class<?> clazz = obj.getClass();483484if (clazz == byte[].class) {485((byte[]) obj)[index] = value;486} else if (clazz == char[].class) {487char[] array = (char[]) obj;488int cidx = index >> 1;489char c = array[cidx];490array[cidx] = (char) storeBits(c, 2, value, 1, index);491} else if (clazz == int[].class) {492int[] array = (int[]) obj;493int iidx = index >> 2;494int i = array[iidx];495array[iidx] = (int) storeBits(i, 4, value, 1, index);496} else if (clazz == long[].class) {497long[] array = (long[]) obj;498int lidx = index >> 3;499long l = array[lidx];500array[lidx] = (long) storeBits(l, 8, value, 1, index);501}502}503504public byte getByteFromArrayByIndex(Object obj, int index) {505Class<?> clazz = obj.getClass();506507if (clazz == byte[].class) {508return ((byte[]) obj)[index];509} else if (clazz == char[].class) {510return (byte) readBits(((char[]) obj)[index >> 1], 2, 1, index);511} else if (clazz == int[].class) {512return (byte) readBits(((int[]) obj)[index >> 2], 4, 1, index);513} else if (clazz == long[].class) {514return (byte) readBits(((long[]) obj)[index >> 3], 8, 1, index);515}516throw new RuntimeException("Unknown array type for bit manipulation");517}518519public void putCharInArrayByIndex(Object obj, int index, char value) {520Class<?> clazz = obj.getClass();521522if (clazz == byte[].class) {523index = index << 1;524byte[] array = (byte[]) obj;525if (!IS_BIG_ENDIAN) {526array[index] = (byte) value;527array[index + 1] = (byte) (value >>> 8);528} else {529array[index] = (byte) (value >>> 8);530array[index + 1] = (byte) value;531}532} else if (clazz == char[].class) {533((char[]) obj)[index] = value;534} else if (clazz == int[].class) {535int[] array = (int[]) obj;536int iidx = index >> 1;537int i = array[iidx];538array[iidx] = (int) storeBits(i, 4, value, 2, index);539} else if (clazz == long[].class) {540long[] array = (long[]) obj;541int lidx = index >> 2;542long l = array[lidx];543array[lidx] = (long) storeBits(l, 8, value, 2, index);544}545}546547public char getCharFromArrayByIndex(Object obj, int index) {548Class<?> clazz = obj.getClass();549550if (clazz == byte[].class) {551index = index << 1;552byte[] array = (byte[]) obj;553if (!IS_BIG_ENDIAN) {554return (char) ((byteToCharUnsigned(array[index + 1]) << 8) | byteToCharUnsigned(array[index]));555} else {556return (char) (byteToCharUnsigned(array[index + 1]) | (byteToCharUnsigned(array[index]) << 8));557}558} else if (clazz == char[].class) {559return ((char[]) obj)[index];560} else if (clazz == int[].class) {561return (char) readBits(((int[]) obj)[index >> 1], 4, 2, index);562} else if (clazz == long[].class) {563return (char) readBits(((long[]) obj)[index >> 2], 8, 2, index);564} else {565throw new RuntimeException("Unknown array type for bit manipulation");566}567}568569/**570* Returns the first index of the target character array within the source character array starting from the specified571* offset.572*573* <p>This API implicitly assumes the following:574* <blockquote><pre>575* - s1Value != null576* - s2Value != null577* - 0 <= s1len <= s1Value.length * 2578* - 1 <= s2len <= s2Value.length * 2579* - 0 <= start < s1len580* <blockquote><pre>581*582* @param s1Value the source character array to search in.583* @param s1len the length (in number of characters) of the source array.584* @param s2Value the target character array to search for.585* @param s2len the length (in number of characters) of the target array.586* @param start the starting offset (in number of characters) to search from.587* @return the index (in number of characters) of the target array within the source array, or -1 if the588* target array is not found within the source array.589*/590public int intrinsicIndexOfStringLatin1(Object s1Value, int s1len, Object s2Value, int s2len, int start) {591char firstChar = byteToCharUnsigned(getByteFromArrayByIndex(s2Value, 0));592593while (true) {594int i = intrinsicIndexOfLatin1(s1Value, (byte)firstChar, start, s1len);595596// Handles subCount > count || start >= count597if (i == -1 || s2len + i > s1len) {598return -1;599}600601int o1 = i;602int o2 = 0;603604while (++o2 < s2len && getByteFromArrayByIndex(s1Value, ++o1) == getByteFromArrayByIndex(s2Value, o2))605;606607if (o2 == s2len) {608return i;609}610611start = i + 1;612}613}614615/**616* Returns the first index of the target character array within the source character array starting from the specified617* offset.618*619* <p>This API implicitly assumes the following:620* <blockquote><pre>621* - s1Value != null622* - s2Value != null623* - 0 <= s1len <= s1Value.length624* - 1 <= s2len <= s2Value.length625* - 0 <= start < s1len626* <blockquote><pre>627*628* @param s1Value the source character array to search in.629* @param s1len the length (in number of characters) of the source array.630* @param s2Value the target character array to search for.631* @param s2len the length (in number of characters) of the target array.632* @param start the starting offset (in number of characters) to search from.633* @return the index (in number of characters) of the target array within the source array, or -1 if the634* target array is not found within the source array.635*/636public int intrinsicIndexOfStringUTF16(Object s1Value, int s1len, Object s2Value, int s2len, int start) {637char firstChar = getCharFromArrayByIndex(s2Value, 0);638639while (true) {640int i = intrinsicIndexOfUTF16(s1Value, firstChar, start, s1len);641642// Handles subCount > count || start >= count643if (i == -1 || s2len + i > s1len) {644return -1;645}646647int o1 = i;648int o2 = 0;649650while (++o2 < s2len && getCharFromArrayByIndex(s1Value, ++o1) == getCharFromArrayByIndex(s2Value, o2))651;652653if (o2 == s2len) {654return i;655}656657start = i + 1;658}659}660661/**662* Returns the first index of the character within the source character array starting from the specified offset.663*664* <p>This API implicitly assumes the following:665* <blockquote><pre>666* - array != null667* - 0 <= offset < length <= array.length * 1 (if array instanceof byte[])668* - 0 <= offset < length <= array.length * 2 (if array instanceof char[])669* <blockquote><pre>670*671* @param array the source character array to search in.672* @param ch the character to search for.673* @param offset the starting offset (in number of characters) to search from.674* @param length the length (in number of characters) of the source array.675* @return the index (in number of characters) of \p ch within the source array, or -1 if \p ch is not found676* within the source array.677*/678public int intrinsicIndexOfLatin1(Object array, byte ch, int offset, int length) {679for (int i = offset; i < length; i++) {680if (getByteFromArrayByIndex(array, i) == ch) {681return i;682}683}684return -1;685}686687/**688* Returns the first index of the character within the source character array starting from the specified offset.689*690* <p>This API implicitly assumes the following:691* <blockquote><pre>692* - array != null693* - 0 <= offset < length <= array.length * 1 (if array instanceof byte[])694* - 0 <= offset < length <= array.length * 2 (if array instanceof char[])695* <blockquote><pre>696*697* @param array the source character array to search in.698* @param ch the character to search for.699* @param offset the starting offset (in number of characters) to search from.700* @param length the length (in number of characters) of the source array.701* @return the index (in number of characters) of \p ch within the source array, or -1 if \p ch is not found702* within the source array.703*/704public int intrinsicIndexOfUTF16(Object array, char ch, int offset, int length) {705for (int i = offset; i < length; i++) {706if (getCharFromArrayByIndex(array, i) == ch) {707return i;708}709}710return -1;711}712713/*714* Constants for optimizedClone715*/716private static final int DESCRIPTION_WORD_SIZE = VM.ADDRESS_SIZE;717private static final int DESCRIPTION_WORD_BIT_SIZE = DESCRIPTION_WORD_SIZE * 8;718// Depends on the definition of slot and whether it's 32 or 64 bit719private static final int SLOT_SIZE = VM.FJ9OBJECT_SIZE;720721private static boolean isDescriptorPointerTagged(int descriptorPtr) {722return (descriptorPtr & 1) == 1;723}724725private static boolean isDescriptorPointerTagged(long descriptorPtr) {726return (descriptorPtr & 1) == 1;727}728729/**730* Called by the JIT on 32bit platforms to copy a source object's contents to a destination object as part of a clone. This is a shallow copy only.731*732* @param srcObj733* The object whose fields are to be copied734* @param destObj735* The object whose fields are to be set (may not be initialized)736* @param j9clazz737* The j9class pointer for the type of the object being copied (usually from a loadaddr)738*/739public final void unsafeObjectShallowCopy32(Object srcObj, Object destObj, int j9clazz) {740int instanceSize = unsafe.getInt(j9clazz + VM.J9CLASS_INSTANCESIZE_OFFSET);741int descriptorPtr = unsafe.getInt(j9clazz + VM.J9CLASS_INSTANCE_DESCRIPTION_OFFSET);742int numSlotsInObject = instanceSize / SLOT_SIZE;743744int descriptorWord = descriptorPtr;745int bitIndex = DESCRIPTION_WORD_BIT_SIZE - 1;746if ((descriptorWord & 1) == 1) {747descriptorWord = descriptorWord >> 1;748} else {749descriptorWord = unsafe.getInt(descriptorPtr);750descriptorPtr = descriptorPtr + DESCRIPTION_WORD_SIZE;751}752753for (int slot = 0; slot < numSlotsInObject; ++slot) {754if (((descriptorWord & 1) == 1)) {755Object fieldValue = getObjectFromObject(srcObj, VM.OBJECT_HEADER_SIZE + (slot * SLOT_SIZE));756putObjectInObject(destObj, VM.OBJECT_HEADER_SIZE + (slot * SLOT_SIZE), fieldValue);757} else {758int fieldValue = getIntFromObject(srcObj, VM.OBJECT_HEADER_SIZE + (slot * SLOT_SIZE));759putIntInObject(destObj, VM.OBJECT_HEADER_SIZE + (slot * SLOT_SIZE), fieldValue);760}761762descriptorWord = descriptorWord >> 1;763if (bitIndex-- == 0) {764descriptorWord = unsafe.getInt(descriptorPtr);765descriptorPtr = descriptorPtr + DESCRIPTION_WORD_SIZE;766bitIndex = DESCRIPTION_WORD_BIT_SIZE - 1;767}768}769770/*771* If the object has a lockword, it needs to be set to the correct initial value since this method772* is effectively the cloned object's initialization.773*/774int lockOffset = unsafe.getInt(j9clazz + VM.J9CLASS_LOCK_OFFSET_OFFSET);775if (lockOffset != 0) {776int lwValue = getInitialLockword32(j9clazz);777putIntInObject(destObj, lockOffset, lwValue);778}779unsafe.storeFence();780}781782/**783* Called by the JIT on 64bit platforms to copy a source object's contents to a destination object as part of a clone. This is a shallow copy only.784*785* @param srcObj786* The object whose fields are to be copied787* @param destObj788* The object whose fields are to be set (may not be initialized)789* @param j9clazz790* The j9class pointer for the type of the object being copied (usually from a loadaddr)791*/792public final void unsafeObjectShallowCopy64(Object srcObj, Object destObj, long j9clazz) {793long instanceSize = unsafe.getLong(j9clazz + VM.J9CLASS_INSTANCESIZE_OFFSET);794long descriptorPtr = unsafe.getLong(j9clazz + VM.J9CLASS_INSTANCE_DESCRIPTION_OFFSET);795int header = VM.OBJECT_HEADER_SIZE;796int numSlotsInObject = (int) (instanceSize / SLOT_SIZE);797798long descriptorWord = descriptorPtr;799int bitIndex = DESCRIPTION_WORD_BIT_SIZE - 1;800if ((descriptorWord & 1) == 1) {801descriptorWord = descriptorWord >> 1;802} else {803descriptorWord = unsafe.getLong(descriptorPtr);804descriptorPtr = descriptorPtr + DESCRIPTION_WORD_SIZE;805}806807for (int slot = 0; slot < numSlotsInObject; ++slot) {808if (((descriptorWord & 1) == 1)) {809Object fieldValue = getObjectFromObject(srcObj, (header + (slot * SLOT_SIZE)));810putObjectInObject(destObj, header + (slot * SLOT_SIZE), fieldValue);811} else {812if (SLOT_SIZE == 4) {813int fieldValue = getIntFromObject(srcObj, header + (slot * SLOT_SIZE));814putIntInObject(destObj, header + (slot * SLOT_SIZE), fieldValue);815} else {816long fieldValue = getLongFromObject(srcObj, header + (slot * SLOT_SIZE));817putLongInObject(destObj, header + (slot * SLOT_SIZE), fieldValue);818}819}820821descriptorWord = descriptorWord >> 1;822if (bitIndex-- == 0) {823descriptorWord = unsafe.getLong(descriptorPtr);824descriptorPtr = descriptorPtr + DESCRIPTION_WORD_SIZE;825bitIndex = DESCRIPTION_WORD_BIT_SIZE - 1;826}827}828829/*830* If the object has a lockword, it needs to be set to the correct initial value since this method831* is effectively the cloned object's initialization.832*/833long lockOffset = unsafe.getLong(j9clazz + VM.J9CLASS_LOCK_OFFSET_OFFSET);834if (lockOffset != 0) {835int lwValue = getInitialLockword64(j9clazz);836if (SLOT_SIZE == 4) {837// for compressed reference, the LockWord is 4 bytes838putIntInObject(destObj, lockOffset, lwValue);839} else {840putLongInObject(destObj, lockOffset, lwValue);841}842}843unsafe.storeFence();844}845846/**847* Java implementation of optimized clone.848*849* @param srcObj850* The source object of the clone.851* @return The cloned object.852*/853public Object optimizedClone(Object srcObj) throws CloneNotSupportedException {854Class<?> clnClass = srcObj.getClass();855856if (clnClass.isArray()) {857Class<?> eleClass = clnClass.getComponentType();858int len = Array.getLength(srcObj);859Object clnObj = Array.newInstance(eleClass, len);860System.arraycopy(srcObj, 0, clnObj, 0, len);861return clnObj;862}863864if (!(srcObj instanceof Cloneable)) {865throw new CloneNotSupportedException();866}867868Object clnObj = null;869try {870clnObj = (Object) unsafe.allocateInstance(clnClass);871} catch (InstantiationException e) {872// This can never actually happen as clnClass is clearly instantiable873}874875int bitIndex = 0;876if (IS_32_BIT) {877int j9clazz = unsafe.getInt(clnClass, JLCLASS_J9CLASS_OFFSET);878// Get the instance size out of the J9Class879int instanceSize = unsafe.getInt(j9clazz + VM.J9CLASS_INSTANCESIZE_OFFSET);880// Get the pointer to instance descriptor out of the J9Class. Tells which fields are refs and prims881int descriptorPtr = unsafe.getInt(j9clazz + VM.J9CLASS_INSTANCE_DESCRIPTION_OFFSET);882int numSlotsInObject = instanceSize / SLOT_SIZE;883int descriptorWord = 0;884if (isDescriptorPointerTagged(descriptorPtr)) {885bitIndex++;886descriptorWord = descriptorPtr >>> 1;887} else {888descriptorWord = unsafe.getInt(descriptorPtr);889}890891int countSlots = 0;892for (int index = 0; numSlotsInObject != 0; index++) {893if (isDescriptorPointerTagged(descriptorWord)) {894Object fieldValue = unsafe.getObject(srcObj, VM.OBJECT_HEADER_SIZE + (countSlots * SLOT_SIZE));895unsafe.putObject(clnObj, VM.OBJECT_HEADER_SIZE + (index * SLOT_SIZE), fieldValue);896} else {897int fieldValue = unsafe.getInt(srcObj, VM.OBJECT_HEADER_SIZE + (countSlots * SLOT_SIZE));898unsafe.putInt(clnObj, VM.OBJECT_HEADER_SIZE + (index * SLOT_SIZE), fieldValue);899}900countSlots++;901if (countSlots >= numSlotsInObject) {902break;903}904if (bitIndex == (DESCRIPTION_WORD_BIT_SIZE - 1)) {905descriptorPtr = descriptorPtr + DESCRIPTION_WORD_SIZE;906bitIndex = 0;907descriptorWord = unsafe.getInt(descriptorPtr);908} else {909descriptorWord = descriptorWord >>> 1;910bitIndex++;911}912}913/* If the object has a lockword, it needs to be set to the correct initial value. */914long lockOffset = unsafe.getInt(j9clazz + VM.J9CLASS_LOCK_OFFSET_OFFSET);915if (lockOffset != 0) {916int lwValue = getInitialLockword32(j9clazz);917unsafe.putInt(clnObj, lockOffset, lwValue);918}919} else {920long j9clazz = unsafe.getLong(clnClass, JLCLASS_J9CLASS_OFFSET);921// Get the instance size out of the J9Class922long instanceSize = unsafe.getLong(j9clazz + VM.J9CLASS_INSTANCESIZE_OFFSET);923// Get the pointer to instance descriptor out of the J9Class. Tells which fields are refs and prims924long descriptorPtr = unsafe.getLong(j9clazz + VM.J9CLASS_INSTANCE_DESCRIPTION_OFFSET);925int numSlotsInObject = (int) (instanceSize / SLOT_SIZE);926long descriptorWord = 0;927if (isDescriptorPointerTagged(descriptorPtr)) {928bitIndex++;929descriptorWord = descriptorPtr >>> 1;930} else {931descriptorWord = unsafe.getLong(descriptorPtr);932}933int countSlots = 0;934for (int index = 0; numSlotsInObject != 0; index++) {935if (isDescriptorPointerTagged(descriptorWord)) {936Object fieldValue = unsafe.getObject(srcObj, VM.OBJECT_HEADER_SIZE + (countSlots * SLOT_SIZE));937unsafe.putObject(clnObj, VM.OBJECT_HEADER_SIZE + (index * SLOT_SIZE), fieldValue);938} else {939long fieldValue = unsafe.getLong(srcObj, VM.OBJECT_HEADER_SIZE + (countSlots * SLOT_SIZE));940unsafe.putLong(clnObj, VM.OBJECT_HEADER_SIZE + (index * SLOT_SIZE), fieldValue);941}942countSlots++;943if (countSlots >= numSlotsInObject) {944break;945}946if (bitIndex == (DESCRIPTION_WORD_BIT_SIZE - 1)) {947descriptorPtr = descriptorPtr + DESCRIPTION_WORD_SIZE;948bitIndex = 0;949descriptorWord = unsafe.getLong(descriptorPtr);950} else {951descriptorWord = descriptorWord >>> 1;952bitIndex++;953}954}955/* If the object has a lockword, it needs to be set to the correct initial value. */956long lockOffset = unsafe.getLong(j9clazz + VM.J9CLASS_LOCK_OFFSET_OFFSET);957if (lockOffset != 0) {958int lwValue = getInitialLockword64(j9clazz);959if (SLOT_SIZE == 4) {960// for compressed reference, the LockWord is 4 bytes961unsafe.putInt(clnObj, lockOffset, lwValue);962} else {963unsafe.putLong(clnObj, lockOffset, lwValue);964}965}966}967968unsafe.storeFence();969return clnObj;970}971972/**973* Get class initialize status flag. Calls to this method will be recognized and optimized by the JIT.974* @parm defc975* The class whose initialize status is desired.976* @return977* initializeStatus from J9Class.978*/979public final int getClassInitializeStatus(Class<?> defc) {980long defcClass = 0;981if (is32Bit()) {982defcClass = getJ9ClassFromClass32(defc);983} else {984defcClass = getJ9ClassFromClass64(defc);985}986int initStatus = 0;987if (4 == VM.ADDRESS_SIZE) {988initStatus = unsafe.getInt(defcClass + VM.J9CLASS_INITIALIZE_STATUS_OFFSET);989} else {990initStatus = (int)unsafe.getLong(defcClass + VM.J9CLASS_INITIALIZE_STATUS_OFFSET);991}992return initStatus;993}994995/**996* Determine initial lockword value, 32-bit version. Calls to this method will return what the lockword should start at.997*998* @parm j9clazz999* The J9Class of the object whose lockword is being initialized.1000*1001* @return1002* The initial lockword to use.1003*/1004public int getInitialLockword32(int j9clazz) {1005int flags = getClassFlagsFromJ9Class32(j9clazz);10061007/*1008* Unsafe calls are used to get the reservedCounter and cancelCounter out of the J9Class.1009* reservedCounter and cancelCounter are unsigned 16 bit values so a mask is used to force a zero extend.1010*/1011int reservedCounter = ((int)(unsafe.getShort(j9clazz + VM.J9CLASS_LOCK_RESERVATION_HISTORY_RESERVED_COUNTER_OFFSET))) & 0xFFFF;1012int cancelCounter = ((int)(unsafe.getShort(j9clazz + VM.J9CLASS_LOCK_RESERVATION_HISTORY_CANCEL_COUNTER_OFFSET))) & 0xFFFF;10131014return getInitialLockword(flags, reservedCounter, cancelCounter);1015}10161017/**1018* Determine initial lockword value, 64-bit version. Calls to this method will return what the lockword should start at.1019*1020* @parm j9clazz1021* The J9Class of the object whose lockword is being initialized.1022*1023* @return1024* The initial lockword to use.1025*/1026public int getInitialLockword64(long j9clazz) {1027int flags = getClassFlagsFromJ9Class64(j9clazz);10281029/*1030* Unsafe calls are used to get the reservedCounter and cancelCounter out of the J9Class.1031* reservedCounter and cancelCounter are unsigned 16 bit values so a mask is used to force a zero extend.1032*/1033int reservedCounter = ((int)(unsafe.getShort(j9clazz + VM.J9CLASS_LOCK_RESERVATION_HISTORY_RESERVED_COUNTER_OFFSET))) & 0xFFFF;1034int cancelCounter = ((int)(unsafe.getShort(j9clazz + VM.J9CLASS_LOCK_RESERVATION_HISTORY_CANCEL_COUNTER_OFFSET))) & 0xFFFF;10351036return getInitialLockword(flags, reservedCounter, cancelCounter);1037}10381039/**1040* Determine initial lockword value. Calls to this method will return what the lockword should start at.1041*1042* @parm flags1043* Class flags from the J9Class.1044*1045* @parm reservedCounter1046* reservedCounter from the J9Class.1047*1048* @parm cancelCounter1049* cancelCounter from the J9Class.1050*1051* @return1052* The initial lockword to use.1053*/1054public int getInitialLockword(int flags, int reservedCounter, int cancelCounter) {1055int lwValue = 0;10561057if (1 == VM.GLR_ENABLE_GLOBAL_LOCK_RESERVATION) {1058/* This path is taken when Global Lock Reservation is enabled. */1059int reservedAbsoluteThreshold = VM.GLR_RESERVED_ABSOLUTE_THRESHOLD;1060int minimumReservedRatio = VM.GLR_MINIMUM_RESERVED_RATIO;10611062int cancelAbsoluteThreshold = VM.GLR_CANCEL_ABSOLUTE_THRESHOLD;1063int minimumLearningRatio = VM.GLR_MINIMUM_LEARNING_RATIO;10641065/*1066* Check reservedCounter and cancelCounter against different thresholds to determine what to initialize the lockword to.1067* First check if the ratio of resevation to cancellations is high enough to set the lockword to the New-AutoReserve state.1068* If so, the initial lockword value is OBJECT_HEADER_LOCK_RESERVED.1069* Second check if the ratio is high enough to set the lockword to the New-PreLearning state.1070* If so, the initial lockword value is OBJECT_HEADER_LOCK_LEARNING.1071* If the ratio is too low, the lockword starts in the Flat-Unlocked state and 0 is returned for the lockword value.1072*1073* Start as New-AutoReserve -> Initial lockword: OBJECT_HEADER_LOCK_RESERVED1074* Start as New-PreLearning -> Initial lockword: OBJECT_HEADER_LOCK_LEARNING1075* Start as Flat-Unlocked -> Initial lockword: 01076*1077* reservedCounter, cancelCounter, minimumReservedRatio and minimumLearningRatio all have a maximum value of 0xFFFF so casting to long1078* is required to guarantee signed overflow does not occur after multiplication.1079*/1080if ((reservedCounter >= reservedAbsoluteThreshold) && ((long)reservedCounter > ((long)cancelCounter * (long)minimumReservedRatio))) {1081lwValue = VM.OBJECT_HEADER_LOCK_RESERVED;1082} else if ((cancelCounter < cancelAbsoluteThreshold) || ((long)reservedCounter > ((long)cancelCounter * (long)minimumLearningRatio))) {1083lwValue = VM.OBJECT_HEADER_LOCK_LEARNING;1084}1085} else if ((flags & VM.J9CLASS_RESERVABLE_LOCK_WORD_INIT) != 0) {1086/* Initialize lockword to New-ReserveOnce. This path is x86 only. */1087lwValue = VM.OBJECT_HEADER_LOCK_RESERVED;1088}10891090return lwValue;1091}10921093/**1094* Determines whether the underlying platform's memory model is big-endian.1095*1096* @return True if the underlying platform's memory model is big-endian, false otherwise.1097*/1098private native static final boolean isBigEndian();10991100/* Placeholder for JIT GPU optimizations - this method never actually gets run */1101public final native void GPUHelper();11021103/*1104* The following natives are recognized and handled specially by the JIT.1105*/11061107public native boolean is32Bit();11081109public native int getNumBitsInReferenceField();11101111public native int getNumBytesInReferenceField();11121113public native int getNumBitsInDescriptionWord();11141115public native int getNumBytesInDescriptionWord();11161117public native int getNumBytesInJ9ObjectHeader();11181119public native int getJ9ClassFromClass32(Class c);11201121public native Class getClassFromJ9Class32(int j9clazz);11221123public native int getTotalInstanceSizeFromJ9Class32(int j9clazz);11241125public native int getInstanceDescriptionFromJ9Class32(int j9clazz);11261127public native int getDescriptionWordFromPtr32(int descriptorPtr);11281129public native long getJ9ClassFromClass64(Class c);11301131public native Class getClassFromJ9Class64(long j9clazz);11321133public native long getTotalInstanceSizeFromJ9Class64(long j9clazz);11341135public native long getInstanceDescriptionFromJ9Class64(long j9clazz);11361137public native long getDescriptionWordFromPtr64(long descriptorPtr);11381139public native int getNumSlotsInObject(Class currentClass);11401141public native int getSlotIndex(Field field);11421143public native boolean isDescriptorPointerTagged(int descriptorPtr, long descriptorPtr64);11441145public native int getRomClassFromJ9Class32(int j9clazz);11461147public native int getSuperClassesFromJ9Class32(int j9clazz);11481149public native int getClassDepthAndFlagsFromJ9Class32(int j9clazz);11501151public native int getBackfillOffsetFromJ9Class32(int j9clazz);11521153public native int getArrayShapeFromRomClass32(int j9romclazz);11541155public native int getModifiersFromRomClass32(int j9romclazz);11561157public native long getRomClassFromJ9Class64(long j9clazz);11581159public native long getSuperClassesFromJ9Class64(long j9clazz);11601161public native long getClassDepthAndFlagsFromJ9Class64(long j9clazz);11621163public native long getBackfillOffsetFromJ9Class64(long j9clazz);11641165public native int getArrayShapeFromRomClass64(long j9romclazz);11661167public native int getModifiersFromRomClass64(long j9romclazz);11681169public native int getClassFlagsFromJ9Class32(int j9clazz);11701171public native int getClassFlagsFromJ9Class64(long j9clazz);11721173public static native void dispatchComputedStaticCall();11741175public static native void dispatchVirtual();1176}117711781179