From 9dab9d33a071a8e03e2d9d7664ed6bb480a426c4 Mon Sep 17 00:00:00 2001 From: Theresa Mammarella Date: Mon, 10 Dec 2018 13:40:38 -0500 Subject: [PATCH 1/4] 12 builds with extensions up to 0b941d8 - new unsafe methods xxReference and natives, invokeCleaner - ImplementMethodHandle.filterArgumentsWithCombiner() - Implement MethodHandle.foldArgumentsWithCombiner() Signed-off-by: Theresa Mammarella --- .../ExternalMessages-MasterIndex.properties | 5 +- .../FilterArgumentsWithCombinerHandle.java | 91 ++++++ .../java/lang/invoke/MethodHandle.java | 20 +- .../java/lang/invoke/MethodHandles.java | 104 +++++- .../classes/jdk/internal/misc/Unsafe.java | 305 +++++++++++++++++- .../codegen/J9RecognizedMethodsEnum.hpp | 6 +- runtime/compiler/env/j9method.cpp | 80 ++++- runtime/oti/VM_MethodHandleKinds.h | 3 +- runtime/oti/vmconstantpool.xml | 9 +- runtime/vm/MHInterpreter.cpp | 136 +++++++- runtime/vm/MHInterpreter.hpp | 37 ++- runtime/vm/bindnatv.cpp | 8 +- 12 files changed, 783 insertions(+), 21 deletions(-) create mode 100644 jcl/src/java.base/share/classes/java/lang/invoke/FilterArgumentsWithCombinerHandle.java diff --git a/jcl/src/java.base/share/classes/com/ibm/oti/util/ExternalMessages-MasterIndex.properties b/jcl/src/java.base/share/classes/com/ibm/oti/util/ExternalMessages-MasterIndex.properties index 5aa7b6ebd88..dc784b7486f 100644 --- a/jcl/src/java.base/share/classes/com/ibm/oti/util/ExternalMessages-MasterIndex.properties +++ b/jcl/src/java.base/share/classes/com/ibm/oti/util/ExternalMessages-MasterIndex.properties @@ -1106,7 +1106,7 @@ K05cc=Cannot assign '{0}' to methodtype '{1}' K05cd=unable to resolve 'bootstrap_method_ref' in '{0}' at index {1} K05ce=Invalid method name: {0} K05cf=illegal setter on final field -K05d0=Can't apply fold of type: {0} to handle of type: {1} starting at {2} +K05d0=Can't apply preprocessor of type: {0} to handle of type: {1} starting at {2} K05d1=cannot have null spread argument unless spreadCount is 0 K05d2=expected '{0}' sized array; encountered '{1}' sized array K05d3=invalid descriptor: {0} @@ -1207,7 +1207,8 @@ K0636="No such field: {0}.{1}({2})" #java.lang.invoke.MethodHandles K0637=The value of {0}: {1} must be in a range from 0 to {2} K0638=The count of argument indices: {0} must be equal to the parameter count of the combiner: {1} -K063A=The return type of combiner: {0} is inconsistent with the argument type of fold handle: {1} at the fold position: {2} +K063A1=The return type of combiner: {0} is inconsistent with the argument type of {1} handle: {2} at the {3} position: {4} +K063A2=The return type of combiner should never be void. K063B=The return type of the try handle: {0} is inconsistent with the return type of the finally handle: {1} K063C=The 1st parameter type of the finally handle: {0} is not {1} K063D=The 2nd parameter type of the finally handle: {0} is inconsistent with the return type of the try handle: {1} diff --git a/jcl/src/java.base/share/classes/java/lang/invoke/FilterArgumentsWithCombinerHandle.java b/jcl/src/java.base/share/classes/java/lang/invoke/FilterArgumentsWithCombinerHandle.java new file mode 100644 index 00000000000..bde4312af73 --- /dev/null +++ b/jcl/src/java.base/share/classes/java/lang/invoke/FilterArgumentsWithCombinerHandle.java @@ -0,0 +1,91 @@ +/*[INCLUDE-IF Java12]*/ +/******************************************************************************* + * Copyright (c) 2018, 2019 IBM Corp. and others + * + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which accompanies this + * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ + * or the Apache License, Version 2.0 which accompanies this distribution and + * is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be madpe available under the following + * Secondary Licenses when the conditions for such availability set + * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU + * General Public License, version 2 with the GNU Classpath + * Exception [1] and GNU General Public License, version 2 with the + * OpenJDK Assembly Exception [2]. + * + * [1] https://www.gnu.org/software/classpath/license.html + * [2] http://openjdk.java.net/legal/assembly-exception.html + * + * 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-exception + *******************************************************************************/ +package java.lang.invoke; + +final class FilterArgumentsWithCombinerHandle extends MethodHandle { + protected final MethodHandle handle; + protected final MethodHandle combiner; + private final int filterPosition; + private final int[] argumentIndices; + + FilterArgumentsWithCombinerHandle(MethodHandle handle, int filterPosition, MethodHandle combiner, int... argumentIndices) { + super(handle.type, KIND_FILTERARGUMENTS_WITHCOMBINER, infoAffectingThunks(combiner.type(), filterPosition, argumentIndices)); + this.handle = handle; + this.combiner = combiner; + this.filterPosition = filterPosition; + this.argumentIndices = argumentIndices; + } + + FilterArgumentsWithCombinerHandle(FilterArgumentsWithCombinerHandle originalHandle, MethodType newType) { + super(originalHandle, newType); + this.handle = originalHandle.handle; + this.combiner = originalHandle.combiner; + this.filterPosition = originalHandle.filterPosition; + this.argumentIndices = originalHandle.argumentIndices; + } + + static FilterArgumentsWithCombinerHandle get(MethodHandle handle, int filterPosition, MethodHandle combiner, int... argumentIndices) { + return new FilterArgumentsWithCombinerHandle(handle, filterPosition, combiner, argumentIndices); + } + + @Override + MethodHandle cloneWithNewType(MethodType newType) { + return new FilterArgumentsWithCombinerHandle(this, newType); + } + + private static Object[] infoAffectingThunks(MethodType combinerType, int filterPosition, int...argumentIndices) { + Object[] result = {combinerType, filterPosition, argumentIndices}; + return result; + } + + private static final ThunkTable _thunkTable = new ThunkTable(); + @Override + protected ThunkTable thunkTable(){ return _thunkTable; } + + @Override + protected final ThunkTuple computeThunks(Object info) { + return thunkTable().get(new ThunkKeyWithObjectArray(ThunkKey.computeThunkableType(type()), (Object[])info)); + } + + private static native int filterPosition(); + private static native int argumentIndices(); + /* create placeholder for combiner based on argumentIndices the original handle's arguments */ + private static native int argumentsForCombiner(int indice, int argPlaceholder); + /* number of arguments remaining after the filtered argument */ + private static native int numSuffixArgs(); + + @FrameIteratorSkip + private final int invokeExact_thunkArchetype_X(int argPlaceholder) { + if (ILGenMacros.isShareableThunk()) { + undoCustomizationLogic(combiner, handle); + } + if (!ILGenMacros.isCustomThunk()) { + doCustomizationLogic(); + } + + return ILGenMacros.invokeExact_X(handle, ILGenMacros.placeholder( + ILGenMacros.firstN(filterPosition(), argPlaceholder), + ILGenMacros.invokeExact(combiner, argumentsForCombiner(argumentIndices(), argPlaceholder)), + ILGenMacros.lastN(numSuffixArgs(), argPlaceholder))); + } +} \ No newline at end of file diff --git a/jcl/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/jcl/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index 458a6f85ccc..ec839fbecb0 100644 --- a/jcl/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/jcl/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -1,6 +1,6 @@ /*[INCLUDE-IF Sidecar17]*/ /******************************************************************************* - * Copyright (c) 2009, 2018 IBM Corp. and others + * Copyright (c) 2009, 2019 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -119,6 +119,9 @@ public abstract class MethodHandle { /*[IF Panama]*/ static final byte KIND_NATIVE = 32; /*[ENDIF]*/ + /*[IF Java12]*/ + static final byte KIND_FILTERARGUMENTS_WITHCOMBINER = 33; + /*[ENDIF]*/ /*[IF Sidecar18-SE-OpenJ9] MethodHandle asTypeCache = null; @@ -1363,6 +1366,21 @@ private MethodHandle returnFilterPlaceHolder() { return this; } + /*[IF Java12]*/ + /*[IF ]*/ + /* + * Used to preserve the MH on the stack when avoiding the call-in for + * filterArgumentsWithCombinerHandle. Must return 'this' so stackmapper will keep the MH + * alive. + */ + /*[ENDIF]*/ + @SuppressWarnings("unused") + @VMCONSTANTPOOL_METHOD + private MethodHandle filterArgumentsWithCombinerPlaceHolder() { + return this; + } + /*[ENDIF]*/ + /*[IF ]*/ /* * Used to preserve the MH on the stack when avoiding the call-in for diff --git a/jcl/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jcl/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index e136d29f795..043352e2470 100644 --- a/jcl/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jcl/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -2791,7 +2791,99 @@ public static MethodHandle filterArguments(MethodHandle handle, int startPositio MethodHandle result = FilterArgumentsHandle.get(handle, startPosition, filters, newType); return result; } + +/*[IF Java12]*/ + /** + * Produce a MethodHandle that preprocesses some of the arguments by calling the preprocessor handle. + * The preprocessor's return type must be the same as the argument in handle at the filterPosition. + * In all cases, the preprocessor handle accepts a subset of the arguments for the handle. + * + * @param handle - the handle to call after preprocessing + * @param filterPosition - the starting position to filter arguments + * @param preprocessor - a methodhandle that preprocesses some of the incoming arguments + * @param argumentIndices - an array of indices of incoming arguments from the handle + * @return a MethodHandle that preprocesses some of the arguments to the handle before calling the next handle + * @throws NullPointerException - if any of the arguments are null + * @throws IllegalArgumentException - if the preprocessor's return type differs from the first argument type of the handle, + * or if the arguments taken by the preprocessor isn't a subset of the arguments to the handle + * or if the element of argumentIndices is outside of the range of the handle's argument list + * or if the arguments specified by argumentIndices from the handle doesn't exactly match the the arguments taken by the preprocessor + */ + static MethodHandle filterArgumentsWithCombiner(MethodHandle handle, int filterPosition, MethodHandle preprocessor, int... argumentIndices) throws NullPointerException, IllegalArgumentException { + + MethodType handleType = handle.type; // implicit nullcheck + MethodType preprocessorType = preprocessor.type; // implicit nullcheck + Class preprocessorReturnClass = preprocessorType.returnType; + final int handleTypeParamCount = handleType.parameterCount(); + final int preprocessorTypeParamCount = preprocessorType.parameterCount(); + final int argIndexCount = argumentIndices.length; + + if ((filterPosition < 0) || (filterPosition >= handleTypeParamCount)) { + /*[MSG "K0637", "The value of {0}: {1} must be in a range from 0 to {2}"]*/ + throw new IllegalArgumentException(Msg.getString("K0637", new Object[] { //$NON-NLS-1$ + "the filter position", Integer.toString(filterPosition), //$NON-NLS-1$ + Integer.toString(handleTypeParamCount)})); + } + if (preprocessorTypeParamCount != argIndexCount) { + /*[MSG "K0638", "The count of argument indices: {0} must be equal to the parameter count of the combiner: {1}"]*/ + throw new IllegalArgumentException(Msg.getString("K0638", new Object[] { //$NON-NLS-1$ + Integer.toString(argIndexCount), + Integer.toString(preprocessorTypeParamCount)})); + } + + for (int i = 0; i < argIndexCount; i++) { + if ((argumentIndices[i] < 0) || (argumentIndices[i] >= handleTypeParamCount)) { + /*[MSG "K0637", "The value of {0}: {1} must be in a range from 0 to {2}"]*/ + throw new IllegalArgumentException(Msg.getString("K0637", new Object[] { //$NON-NLS-1$ + "argument index", Integer.toString(argumentIndices[i]), //$NON-NLS-1$ + Integer.toString(handleTypeParamCount)})); + } + } + + if (void.class == preprocessorReturnClass) { + /*[MSG "K063A2", "The return type of combiner should never be void."]*/ + throw new IllegalArgumentException(Msg.getString("K063A2")); //$NON-NLS-1$ + } + + if (preprocessorReturnClass != handleType.arguments[filterPosition]) { + /*[MSG "K063A1", "The return type of combiner: {0} is inconsistent with the argument type of {1} handle: {2} at the {3} position: {4}"]*/ + throw new IllegalArgumentException(Msg.getString("K063A1", new Object[] { //$NON-NLS-1$ + preprocessorReturnClass.getSimpleName(), "filter", + handleType.arguments[filterPosition].getSimpleName(), "filter", + Integer.toString(filterPosition)})); + } + + validateParametersOfCombiner(argIndexCount, preprocessorTypeParamCount, preprocessorType, handleType, argumentIndices, filterPosition, 1); + + MethodHandle result = FilterArgumentsWithCombinerHandle.get(handle, filterPosition, preprocessor, argumentIndices); + + return result; + } + + /** + * Produce a MethodHandle that preprocesses some of the arguments by calling the preprocessor handle. + * + * If the preprocessor handle has a return type, it must be the same as the argument type at foldPosition of the handle. + * If the preprocessor returns void, it does not contribute the first argument to the handle. + * In all cases, the preprocessor handle accepts a subset of the arguments for the handle. + * + * @param handle - the handle to call after preprocessing + * @param foldPosition - the starting position to fold arguments + * @param preprocessor - a methodhandle that preprocesses some of the incoming arguments + * @param argumentIndices - an array of indices of incoming arguments from the handle + * @return a MethodHandle that preprocesses some of the arguments to the handle before calling the next handle, possibly with an additional first argument + * @throws NullPointerException - if any of the arguments are null + * @throws IllegalArgumentException - if the preprocessor's return type is not void and it differs from the first argument type of the handle, + * or if the arguments taken by the preprocessor isn't a subset of the arguments to the handle + * or if the element of argumentIndices is outside of the range of the handle's argument list + * or if the arguments specified by argumentIndices from the handle doesn't exactly match the the arguments taken by the preprocessor + */ + static MethodHandle foldArgumentsWithCombiner(MethodHandle handle, int foldPosition, MethodHandle preprocessor, int... argumentIndices) throws NullPointerException, IllegalArgumentException { + return foldArguments(handle, foldPosition, preprocessor, argumentIndices); + } +/*[ENDIF]*/ + /** * Produce a MethodHandle that preprocesses some of the arguments by calling the preprocessor handle. * @@ -2926,10 +3018,10 @@ private static final MethodHandle foldArgumentsCommon(MethodHandle handle, int f "<", Integer.toString(handleTypeParamCount)})); //$NON-NLS-1$ } if (preprocessorReturnClass != handleType.arguments[foldPosition]) { - /*[MSG "K063A", "The return type of combiner: {0} is inconsistent with the argument type of fold handle: {1} at the fold position: {2}"]*/ - throw new IllegalArgumentException(Msg.getString("K063A", new Object[] { //$NON-NLS-1$ - preprocessorReturnClass.getSimpleName(), - handleType.arguments[foldPosition].getSimpleName(), + /*[MSG "K063A1", "The return type of combiner: {0} is inconsistent with the argument type of {1} handle: {2} at the {3} position: {4}"]*/ + throw new IllegalArgumentException(Msg.getString("K063A1", new Object[] { //$NON-NLS-1$ + preprocessorReturnClass.getSimpleName(), "filter", + handleType.arguments[foldPosition].getSimpleName(), "filter", Integer.toString(foldPosition)})); } validateParametersOfCombiner(argIndexCount, preprocessorTypeParamCount, preprocessorType, handleType, argumentIndices, foldPosition, 1); @@ -2942,14 +3034,14 @@ private static void validateParametersOfCombiner(int argIndexCount, int preproce if (0 == argIndexCount) { for (int i = 0; i < preprocessorTypeParamCount; i++) { if (preprocessorType.arguments[i] != handleType.arguments[foldPosition + i + foldPlaceHolder]) { - /*[MSG "K05d0", "Can't apply fold of type: {0} to handle of type: {1} starting at {2} "]*/ + /*[MSG "K05d0", "Can't apply preprocessor of type: {0} to handle of type: {1} starting at {2} "]*/ throw new IllegalArgumentException(Msg.getString("K05d0", preprocessorType.toString(), handleType.toString(), Integer.toString(foldPosition))); //$NON-NLS-1$ } } } else { for (int i = 0; i < argIndexCount; i++) { if (preprocessorType.arguments[i] != handleType.arguments[argumentIndices[i]]) { - /*[MSG "K05d0", "Can't apply fold of type: {0} to handle of type: {1} starting at {2} "]*/ + /*[MSG "K05d0", "Can't apply preprocessor of type: {0} to handle of type: {1} starting at {2} "]*/ throw new IllegalArgumentException(Msg.getString("K05d0", preprocessorType.toString(), handleType.toString(), Integer.toString(foldPosition))); //$NON-NLS-1$ } } diff --git a/jcl/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/jcl/src/java.base/share/classes/jdk/internal/misc/Unsafe.java index a5991c592b7..6f119011c15 100644 --- a/jcl/src/java.base/share/classes/jdk/internal/misc/Unsafe.java +++ b/jcl/src/java.base/share/classes/jdk/internal/misc/Unsafe.java @@ -1,6 +1,6 @@ /*[INCLUDE-IF Sidecar19-SE-OpenJ9]*/ /******************************************************************************* - * Copyright (c) 2017, 2018 IBM Corp. and others + * Copyright (c) 2017, 2019 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -30,6 +30,9 @@ import java.lang.reflect.Field; import java.security.ProtectionDomain; import java.util.Objects; +/*[IF Java12]*/ +import java.nio.ByteBuffer; +/*[ENDIF]*/ public final class Unsafe { @@ -400,6 +403,28 @@ public final class Unsafe { * @param value Object to store in obj */ public native void putObject(Object obj, long offset, Object value); + +/*[IF Java12]*/ + /** + * Gets the value of the Object in the obj parameter referenced by offset. + * This is a non-volatile operation. + * + * @param obj object from which to retrieve the value + * @param offset position of the value in obj + * @return Object value stored in obj + */ + public native Object getReference(Object obj, long offset); + + /** + * Sets the value of the Object in the obj parameter at memory offset. + * This is a non-volatile operation. + * + * @param obj object into which to store the value + * @param offset position of the value in obj + * @param value Object to store in obj + */ + public native void putReference(Object obj, long offset, Object value); +/*[ENDIF]*/ /** * Gets the value of the Object in memory referenced by address. @@ -571,6 +596,37 @@ public native Class defineClass0(String name, byte[] b, int offset, int bLeng public final native Object compareAndExchangeObject(Object obj, long offset, Object compareValue, Object exchangeValue); +/*[IF Java12]*/ + /** + * Atomically sets the parameter value at offset in obj if the compare value + * matches the existing value in the object. + * The get operation has memory semantics of getVolatile. + * The set operation has the memory semantics of setVolatile. + * + * @param obj object into which to store the value + * @param offset location to compare and store value in obj + * @param compareValue value that is expected to be in obj at offset + * @param setValue value that will be set in obj at offset if compare is successful + * @return boolean value indicating whether the field was updated + */ + public final native boolean compareAndSetReference(Object obj, long offset, Object compareValue, Object setValue); + + /** + * Atomically sets the parameter value at offset in obj if the compare value + * matches the existing value in the object. + * The get operation has memory semantics of getVolatile. + * The set operation has the memory semantics of setVolatile. + * + * @param obj object into which to store the value + * @param offset location to compare and store value in obj + * @param compareValue value that is expected to be in obj at offset + * @param exchangeValue value that will be set in obj at offset if compare is successful + * @return value in obj at offset before this operation. This will be compareValue if the exchange was successful + */ + public final native Object compareAndExchangeReference(Object obj, long offset, Object compareValue, + Object exchangeValue); +/*[ENDIF]*/ + /** * Atomically gets the value of the byte in the obj parameter referenced by offset. * @@ -733,6 +789,26 @@ public final native Object compareAndExchangeObject(Object obj, long offset, Obj */ public native void putObjectVolatile(Object obj, long offset, Object value); +/*[IF Java12]*/ + /** + * Atomically gets the value of the Object in the obj parameter referenced by offset. + * + * @param obj object from which to retrieve the value + * @param offset position of the value in obj + * @return Object value stored in obj + */ + public native Object getReferenceVolatile(Object obj, long offset); + + /** + * Atomically sets the value of the Object in the obj parameter at memory offset. + * + * @param obj object into which to store the value + * @param offset position of the value in obj + * @param value Object to store in obj + */ + public native void putReferenceVolatile(Object obj, long offset, Object value); +/*[ENDIF]*/ + /** * Makes permit available for thread parameter. * @@ -2704,6 +2780,106 @@ public final boolean weakCompareAndSetObject(Object obj, long offset, Object com return compareAndSetObject(obj, offset, compareValue, setValue); } +/*[IF Java12]*/ + /** + * Atomically sets the parameter value at offset in obj if the compare value + * matches the existing value in the object. + * The get operation has memory semantics of getAcquire. + * The set operation has the memory semantics of set. + * + * @param obj object into which to store the value + * @param offset location to compare and store value in obj + * @param compareValue value that is expected to be in obj at offset + * @param exchangeValue value that will be set in obj at offset if compare is successful + * @return value in obj at offset before this operation. This will be compareValue if the exchange was successful + */ + public final Object compareAndExchangeReferenceAcquire(Object obj, long offset, Object compareValue, + Object exchangeValue) { + return compareAndExchangeReference(obj, offset, compareValue, exchangeValue); + } + + /** + * Atomically sets the parameter value at offset in obj if the compare value + * matches the existing value in the object. + * The get operation has memory semantics of get. + * The set operation has the memory semantics of setRelease. + * + * @param obj object into which to store the value + * @param offset location to compare and store value in obj + * @param compareValue value that is expected to be in obj at offset + * @param exchangeValue value that will be set in obj at offset if compare is successful + * @return value in obj at offset before this operation. This will be compareValue if the exchange was successful + */ + public final Object compareAndExchangeReferenceRelease(Object obj, long offset, Object compareValue, + Object exchangeValue) { + return compareAndExchangeReference(obj, offset, compareValue, exchangeValue); + } + + /** + * Sets the parameter value at offset in obj if the compare value + * matches the existing value in the object. + * The get operation has memory semantics of get. + * The set operation has the memory semantics of set. + * + * @param obj object into which to store the value + * @param offset location to compare and store value in obj + * @param compareValue value that is expected to be in obj at offset + * @param setValue value that will be set in obj at offset if compare is successful + * @return boolean value indicating whether the field was updated + */ + public final boolean weakCompareAndSetReferencePlain(Object obj, long offset, Object compareValue, Object setValue) { + return compareAndSetReference(obj, offset, compareValue, setValue); + } + + /** + * Sets the parameter value at offset in obj if the compare value + * matches the existing value in the object. + * The get operation has memory semantics of getAcquire. + * The set operation has the memory semantics of set. + * + * @param obj object into which to store the value + * @param offset location to compare and store value in obj + * @param compareValue value that is expected to be in obj at offset + * @param setValue value that will be set in obj at offset if compare is successful + * @return boolean value indicating whether the field was updated + */ + public final boolean weakCompareAndSetReferenceAcquire(Object obj, long offset, Object compareValue, Object setValue) { + return compareAndSetReference(obj, offset, compareValue, setValue); + } + + /** + * Sets the parameter value at offset in obj if the compare value + * matches the existing value in the object. + * The get operation has memory semantics of get. + * The set operation has the memory semantics of setRelease. + * + * @param obj object into which to store the value + * @param offset location to compare and store value in obj + * @param compareValue value that is expected to be in obj at offset + * @param setValue value that will be set in obj at offset if compare is successful + * @return boolean value indicating whether the field was updated + */ + public final boolean weakCompareAndSetReferenceRelease(Object obj, long offset, Object compareValue, Object setValue) { + return compareAndSetReference(obj, offset, compareValue, setValue); + } + + /** + * Sets the parameter value at offset in obj if the compare value + * matches the existing value in the object. + * The get operation has memory semantics of get. + * The set operation has the memory semantics of set. + * + * @param obj object into which to store the value + * @param offset location to compare and store value in obj + * @param compareValue value that is expected to be in obj at offset + * @param setValue value that will be set in obj at offset if compare is successful + * @return boolean value indicating whether the field was updated + */ + public final boolean weakCompareAndSetReference(Object obj, long offset, Object compareValue, Object setValue) { + return compareAndSetReference(obj, offset, compareValue, setValue); + } +/*[ENDIF]*/ + /** * Gets the value of the byte in the obj parameter referenced by offset using acquire semantics. * Preceding loads will not be reordered with subsequent loads/stores. @@ -2812,6 +2988,20 @@ public final Object getObjectAcquire(Object obj, long offset) { return getObjectVolatile(obj, offset); } + /*[IF Java12]*/ + /** + * Gets the value of the Object in the obj parameter referenced by offset using acquire semantics. + * Preceding loads will not be reordered with subsequent loads/stores. + * + * @param obj object from which to retrieve the value + * @param offset position of the value in obj + * @return Object value stored in obj + */ + public final Object getReferenceAcquire(Object obj, long offset) { + return getReferenceVolatile(obj, offset); + } + /*[ENDIF]*/ + /** * Sets the value of the byte in the obj parameter at memory offset using acquire semantics. * Preceding stores will not be reordered with subsequent loads/stores. @@ -2919,6 +3109,20 @@ public final void putBooleanRelease(Object obj, long offset, boolean value) { public final void putObjectRelease(Object obj, long offset, Object value) { putObjectVolatile(obj, offset, value); } + +/*[IF Java12]*/ + /** + * Sets the value of the Object in the obj parameter at memory offset using acquire semantics. + * Preceding stores will not be reordered with subsequent loads/stores. + * + * @param obj object into which to store the value + * @param offset position of the value in obj + * @param value Object to store in obj + */ + public final void putReferenceRelease(Object obj, long offset, Object value) { + putReferenceVolatile(obj, offset, value); + } +/*[ENDIF]*/ /** * Gets the value of the byte in the obj parameter referenced by offset. @@ -3028,6 +3232,20 @@ public final Object getObjectOpaque(Object obj, long offset) { return getObjectVolatile(obj, offset); } +/*[IF Java12]*/ + /** + * Gets the value of the Object in the obj parameter referenced by offset. + * The operation is in program order, but does enforce ordering with respect to other threads. + * + * @param obj object from which to retrieve the value + * @param offset position of the value in obj + * @return Object value stored in obj + */ + public final Object getReferenceOpaque(Object obj, long offset) { + return getReferenceVolatile(obj, offset); + } +/*[ENDIF]*/ + /** * Sets the value of the byte in the obj parameter at memory offset. * The operation is in program order, but does enforce ordering with respect to other threads. @@ -3136,6 +3354,20 @@ public final void putObjectOpaque(Object obj, long offset, Object value) { putObjectVolatile(obj, offset, value); } +/*[IF Java12]*/ + /** + * Sets the value of the Object in the obj parameter at memory offset. + * The operation is in program order, but does enforce ordering with respect to other threads. + * + * @param obj object into which to store the value + * @param offset position of the value in obj + * @param value Object to store in obj + */ + public final void putReferenceOpaque(Object obj, long offset, Object value) { + putReferenceVolatile(obj, offset, value); + } +/*[ENDIF]*/ + /** * Get the load average in the system. * @@ -4092,6 +4324,68 @@ public final Object getAndSetObjectAcquire(Object obj, long offset, Object value } } +/*[IF Java12]*/ + /** + * Atomically sets value at offset in obj + * and returns the value of the field prior to the update. + * The get operation has the memory semantics of getVolatile. + * The set operation has the memory semantics of setVolatile. + * + * @param obj object into which to set the value + * @param offset location to set value in obj + * @param value to set in obj memory + * @return value of field in obj at offset before update + */ + public final Object getAndSetReference(Object obj, long offset, Object value) { + for (;;) { + Object objectAtOffset = getReferenceVolatile(obj, offset); + if (weakCompareAndSetReference(obj, offset, objectAtOffset, value)) { + return objectAtOffset; + } + } + } + + /** + * Atomically sets value at offset in obj + * and returns the value of the field prior to the update. + * The get operation has the memory semantics of get. + * The set operation has the memory semantics of setRelease. + * + * @param obj object into which to set the value + * @param offset location to set value in obj + * @param value to set in obj memory + * @return value of field in obj at offset before update + */ + public final Object getAndSetReferenceRelease(Object obj, long offset, Object value) { + for (;;) { + Object objectAtOffset = getReference(obj, offset); + if (weakCompareAndSetReferenceRelease(obj, offset, objectAtOffset, value)) { + return objectAtOffset; + } + } + } + + /** + * Atomically sets value at offset in obj + * and returns the value of the field prior to the update. + * The get operation has the memory semantics of getAcquire. + * The set operation has the memory semantics of set. + * + * @param obj object into which to set the value + * @param offset location to set value in obj + * @param value to set in obj memory + * @return value of field in obj at offset before update + */ + public final Object getAndSetReferenceAcquire(Object obj, long offset, Object value) { + for (;;) { + Object objectAtOffset = getReferenceAcquire(obj, offset); + if (weakCompareAndSetReferenceAcquire(obj, offset, objectAtOffset, value)) { + return objectAtOffset; + } + } + } +/*[ENDIF]*/ + /** * Atomically OR's the given value to the current value of the * field at offset in obj and returns the value of the field prior @@ -5536,6 +5830,15 @@ public final void putCharUnaligned(Object obj, long offset, char value, boolean putCharUnaligned(obj, offset, endianValue); } +/*[IF Java12]*/ + /** + * Stub for Java 12 compilation + */ + public void invokeCleaner(ByteBuffer arg) { + throw new UnsupportedOperationException("Stub for Java 12 compilation"); //$NON-NLS-1$ + } +/*[ENDIF]*/ + /* * Private methods */ diff --git a/runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp b/runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp index 7038538d5b9..8037086d942 100644 --- a/runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp +++ b/runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corp. and others + * Copyright (c) 2000, 2019 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -956,6 +956,10 @@ java_lang_invoke_FoldHandle_argIndices, java_lang_invoke_FoldHandle_argumentsForCombiner, java_lang_invoke_FoldHandle_foldPosition, + java_lang_invoke_FilterArgumentsWithCombinerHandle_filterPosition, + java_lang_invoke_FilterArgumentsWithCombinerHandle_argumentIndices, + java_lang_invoke_FilterArgumentsWithCombinerHandle_argumentsForCombiner, + java_lang_invoke_FilterArgumentsWithCombinerHandle_numSuffixArgs, java_lang_invoke_GuardWithTestHandle_numGuardArgs, java_lang_invoke_ILGenMacros_arrayElements, java_lang_invoke_ILGenMacros_arrayLength, diff --git a/runtime/compiler/env/j9method.cpp b/runtime/compiler/env/j9method.cpp index 09a5914b83c..88932c7c4a4 100644 --- a/runtime/compiler/env/j9method.cpp +++ b/runtime/compiler/env/j9method.cpp @@ -3861,7 +3861,7 @@ TR_ResolvedJ9Method::TR_ResolvedJ9Method(TR_OpaqueMethodBlock * aMethod, TR_Fron static X VarHandleMethods[] = { - // Recognized method only works for resovled methods + // Recognized method only works for resolved methods // Resolved VarHandle access methods are suffixed with _impl in their names // A list for unresolved VarHandle access methods is in VarHandleTransformer.cpp, // changes in the following list need to be reflected in the other @@ -4021,6 +4021,14 @@ TR_ResolvedJ9Method::TR_ResolvedJ9Method(TR_OpaqueMethodBlock * aMethod, TR_Fron { TR::java_lang_invoke_FoldHandle_argumentsForCombiner, 20, "argumentsForCombiner", (int16_t)-1, "*"}, { TR::unknownMethod} }; + static X FilterArgumentsWithCombinerHandleMethods[] = + { + {x(TR::java_lang_invoke_FilterArgumentsWithCombinerHandle_filterPosition, "filterPosition", "()I")}, + {x(TR::java_lang_invoke_FilterArgumentsWithCombinerHandle_argumentIndices, "argumentIndices", "()I")}, + {x(TR::java_lang_invoke_FilterArgumentsWithCombinerHandle_numSuffixArgs, "numSuffixArgs", "()I")}, + { TR::java_lang_invoke_FilterArgumentsWithCombinerHandle_argumentsForCombiner, 20, "argumentsForCombiner", (int16_t)-1, "*"}, + { TR::unknownMethod} + }; static X FinallyHandleMethods[]= { @@ -4241,6 +4249,7 @@ TR_ResolvedJ9Method::TR_ResolvedJ9Method(TR_OpaqueMethodBlock * aMethod, TR_Fron struct Y { const char * _class; X * _methods; }; + /* classXX where XX is the number of characters in the class name */ static Y class13[] = { { "java/nio/Bits", BitsMethods }, @@ -4535,6 +4544,7 @@ TR_ResolvedJ9Method::TR_ResolvedJ9Method(TR_OpaqueMethodBlock * aMethod, TR_Fron static Y class50[] = { { "java/util/concurrent/atomic/AtomicLongFieldUpdater", JavaUtilConcurrentAtomicLongFieldUpdaterMethods }, + { "java/lang/invoke/FilterArgumentsWithCombinerHandle", FilterArgumentsWithCombinerHandleMethods }, { 0 } }; @@ -8135,6 +8145,29 @@ TR_J9ByteCodeIlGenerator::runFEMacro(TR::SymbolReference *symRef) } return true; } + case TR::java_lang_invoke_FilterArgumentsWithCombinerHandle_argumentIndices: + { + TR_ASSERT(archetypeParmCount == 0, "assertion failure"); // The number of arguments for argumentIndices() + J9::MethodHandleThunkDetails *thunkDetails = getMethodHandleThunkDetails(this, comp(), symRef); + if (!thunkDetails) + return false; + + uintptrj_t methodHandle; + uintptrj_t argumentIndices; + { + TR::VMAccessCriticalSection invokeFilterArgumentsWithCombinerHandle(fej9); + methodHandle = *thunkDetails->getHandleRef(); + argumentIndices = fej9->getReferenceField(methodHandle, "argumentIndices", "[I"); + int32_t arrayLength = (int32_t)fej9->getArrayLengthInElements(argumentIndices); + // Push the indices in reverse order + for (int i = arrayLength - 1; i >= 0; i--) { + int32_t index = fej9->getInt32Element(argumentIndices, i); + loadConstant(TR::iconst, index); + } + loadConstant(TR::iconst, arrayLength); // number of arguments + } + return true; + } case TR::java_lang_invoke_FoldHandle_foldPosition: { TR_ASSERT(archetypeParmCount == 0, "assertion failure"); // The number of arguments for foldPosition() @@ -8154,7 +8187,27 @@ TR_J9ByteCodeIlGenerator::runFEMacro(TR::SymbolReference *symRef) loadConstant(TR::iconst, foldPosition); return true; } + case TR::java_lang_invoke_FilterArgumentsWithCombinerHandle_filterPosition: + { + TR_ASSERT(archetypeParmCount == 0, "assertion failure"); // The number of arguments for filterPosition() + + J9::MethodHandleThunkDetails *thunkDetails = getMethodHandleThunkDetails(this, comp(), symRef); + if (!thunkDetails) + return false; + + uintptrj_t methodHandle; + int32_t filterPosition; + { + TR::VMAccessCriticalSection invokeFilterArgumentsWithCombinerHandle(fej9); + methodHandle = *thunkDetails->getHandleRef(); + filterPosition = fej9->getInt32Field(methodHandle, "filterPosition"); + } + + loadConstant(TR::iconst, filterPosition); + return true; + } case TR::java_lang_invoke_FoldHandle_argumentsForCombiner: + case TR::java_lang_invoke_FilterArgumentsWithCombinerHandle_argumentsForCombiner: { TR::Node *placeholder = genNodeAndPopChildren(TR::icall, 1, placeholderWithDummySignature()); @@ -8220,7 +8273,30 @@ TR_J9ByteCodeIlGenerator::runFEMacro(TR::SymbolReference *symRef) loadConstant(TR::iconst, numArgsPassToFinallyTarget); return true; } + case TR::java_lang_invoke_FilterArgumentsWithCombinerHandle_numSuffixArgs: + { + TR_ASSERT(archetypeParmCount == 0, "assertion failure"); + J9::MethodHandleThunkDetails *thunkDetails = getMethodHandleThunkDetails(this, comp(), symRef); + if (!thunkDetails) + return false; + + uintptrj_t methodHandle; + uintptrj_t arguments; + int32_t numArguments; + int32_t filterPos; + + { + TR::VMAccessCriticalSection invokeFilterArgumentsWithCombinerHandle(fej9); + methodHandle = *thunkDetails->getHandleRef(); + arguments = fej9->getReferenceField(fej9->methodHandle_type(methodHandle), "arguments", "[Ljava/lang/Class;"); + numArguments = (int32_t)fej9->getArrayLengthInElements(arguments); + filterPos = (int32_t)fej9->getInt32Field(methodHandle, "filterPosition"); + } + + loadConstant(TR::iconst, numArguments - (filterPos + 1)); + return true; + } case TR::java_lang_invoke_FilterArgumentsHandle_numPrefixArgs: case TR::java_lang_invoke_FilterArgumentsHandle_numSuffixArgs: case TR::java_lang_invoke_FilterArgumentsHandle_numArgsToFilter: @@ -8239,7 +8315,7 @@ TR_J9ByteCodeIlGenerator::runFEMacro(TR::SymbolReference *symRef) int32_t numFilters; { - TR::VMAccessCriticalSection invokeFilderArgumentsHandle(fej9); + TR::VMAccessCriticalSection invokeFilterArgumentsHandle(fej9); methodHandle = *thunkDetails->getHandleRef(); arguments = fej9->getReferenceField(fej9->methodHandle_type(methodHandle), "arguments", "[Ljava/lang/Class;"); numArguments = (int32_t)fej9->getArrayLengthInElements(arguments); diff --git a/runtime/oti/VM_MethodHandleKinds.h b/runtime/oti/VM_MethodHandleKinds.h index 13ae1bc0e1e..6e5eb088208 100644 --- a/runtime/oti/VM_MethodHandleKinds.h +++ b/runtime/oti/VM_MethodHandleKinds.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 1991, 2018 IBM Corp. and others + * Copyright (c) 1991, 2019 IBM Corp. and others * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this @@ -58,5 +58,6 @@ #ifdef J9VM_OPT_PANAMA #define J9_METHOD_HANDLE_KIND_NATIVE 0x20 #endif +#define J9_METHOD_HANDLE_KIND_FILTER_ARGUMENTS_WITH_COMBINER 0x21 #endif /* VM_METHODHANDLEKINDS_H_ */ diff --git a/runtime/oti/vmconstantpool.xml b/runtime/oti/vmconstantpool.xml index f69048a85c2..8fe7f21a734 100644 --- a/runtime/oti/vmconstantpool.xml +++ b/runtime/oti/vmconstantpool.xml @@ -1,6 +1,6 @@