Skip to content

Commit

Permalink
8316742: [lworld] Intrinsify Unsafe::isFlattenedArray()
Browse files Browse the repository at this point in the history
Reviewed-by: thartmann
  • Loading branch information
robcasloz authored and TobiHartmann committed Oct 18, 2023
1 parent 3a5d7d9 commit 985474d
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 8 deletions.
1 change: 1 addition & 0 deletions make/test/BuildMicrobenchmark.gmk
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
--add-exports java.base/jdk.internal.classfile.instruction=ALL-UNNAMED \
--add-exports java.base/jdk.internal.classfile.components=ALL-UNNAMED \
--add-exports java.base/jdk.internal.classfile.impl=ALL-UNNAMED \
--add-exports java.base/jdk.internal.misc=ALL-UNNAMED \
--add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \
--add-exports java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED \
--add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
Expand Down
2 changes: 2 additions & 0 deletions src/hotspot/share/classfile/vmIntrinsics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,8 @@ class methodHandle;
do_intrinsic(_copyMemory, jdk_internal_misc_Unsafe, copyMemory_name, copyMemory_signature, F_RN) \
do_name( copyMemory_name, "copyMemory0") \
do_signature(copyMemory_signature, "(Ljava/lang/Object;JLjava/lang/Object;JJ)V") \
do_intrinsic(_isFlattenedArray, jdk_internal_misc_Unsafe, isFlattenedArray_name, class_boolean_signature, F_RN) \
do_name( isFlattenedArray_name, "isFlattenedArray") \
do_intrinsic(_loadFence, jdk_internal_misc_Unsafe, loadFence_name, loadFence_signature, F_R) \
do_name( loadFence_name, "loadFence") \
do_alias( loadFence_signature, void_method_signature) \
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/opto/c2compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) {
case vmIntrinsics::_nanoTime:
case vmIntrinsics::_allocateInstance:
case vmIntrinsics::_allocateUninitializedArray:
case vmIntrinsics::_isFlattenedArray:
case vmIntrinsics::_newArray:
case vmIntrinsics::_getLength:
case vmIntrinsics::_copyOf:
Expand Down
15 changes: 15 additions & 0 deletions src/hotspot/share/opto/library_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ bool LibraryCallKit::try_to_inline(int predicate) {
case vmIntrinsics::_writebackPostSync0: return inline_unsafe_writebackSync0(false);
case vmIntrinsics::_allocateInstance: return inline_unsafe_allocate();
case vmIntrinsics::_copyMemory: return inline_unsafe_copyMemory();
case vmIntrinsics::_isFlattenedArray: return inline_unsafe_isFlattenedArray();
case vmIntrinsics::_getLength: return inline_native_getLength();
case vmIntrinsics::_copyOf: return inline_array_copyOf(false);
case vmIntrinsics::_copyOfRange: return inline_array_copyOf(true);
Expand Down Expand Up @@ -5261,6 +5262,20 @@ bool LibraryCallKit::inline_unsafe_copyMemory() {

#undef XTOP

//----------------------inline_unsafe_isFlattenedArray-------------------
// public native boolean Unsafe.isFlattenedArray(Class<?> arrayClass);
// This intrinsic exploits assumptions made by the native implementation
// (arrayClass is neither null nor primitive) to avoid unnecessary null checks.
bool LibraryCallKit::inline_unsafe_isFlattenedArray() {
Node* cls = argument(1);
Node* p = basic_plus_adr(cls, java_lang_Class::klass_offset());
Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, nullptr, immutable_memory(), p,
TypeRawPtr::BOTTOM, TypeInstKlassPtr::OBJECT));
Node* result = flat_array_test(kls);
set_result(result);
return true;
}

//------------------------clone_coping-----------------------------------
// Helper function for inline_native_clone.
void LibraryCallKit::copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, bool is_array) {
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/opto/library_call.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ class LibraryCallKit : public GraphKit {
bool inline_unsafe_writeback0();
bool inline_unsafe_writebackSync0(bool is_pre);
bool inline_unsafe_copyMemory();
bool inline_unsafe_isFlattenedArray();
bool inline_unsafe_make_private_buffer();
bool inline_unsafe_finish_private_buffer();

Expand Down
16 changes: 14 additions & 2 deletions src/hotspot/share/opto/macro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2819,7 +2819,7 @@ void PhaseMacroExpand::expand_flatarraycheck_node(FlatArrayCheckNode* check) {
Node* klass_adr = basic_plus_adr(array_or_klass, oopDesc::klass_offset_in_bytes());
klass = transform_later(LoadKlassNode::make(_igvn, nullptr, C->immutable_memory(), klass_adr, TypeInstPtr::KLASS, TypeInstKlassPtr::OBJECT));
} else {
assert(t->isa_aryklassptr(), "Unexpected input type");
assert(t->isa_klassptr(), "Unexpected input type");
klass = array_or_klass;
}
Node* lh_addr = basic_plus_adr(klass, in_bytes(Klass::layout_helper_offset()));
Expand All @@ -2829,8 +2829,20 @@ void PhaseMacroExpand::expand_flatarraycheck_node(FlatArrayCheckNode* check) {
Node* masked = transform_later(new AndINode(lhs, intcon(Klass::_lh_array_tag_flat_value_bit_inplace)));
Node* cmp = transform_later(new CmpINode(masked, intcon(0)));
Node* bol = transform_later(new BoolNode(cmp, BoolTest::eq));
Node* m2b = transform_later(new Conv2BNode(masked));
// The matcher expects the input to If nodes to be produced by a Bool(CmpI..)
// pattern, but the input to other potential users (e.g. Phi) to be some
// other pattern (e.g. a Conv2B node, possibly idealized as a CMoveI).
Node* old_bol = check->unique_out();
_igvn.replace_node(old_bol, bol);
for (DUIterator_Last imin, i = old_bol->last_outs(imin); i >= imin; --i) {
Node* user = old_bol->last_out(i);
for (uint j = 0; j < user->req(); j++) {
Node* n = user->in(j);
if (n == old_bol) {
_igvn.replace_input_of(user, j, user->is_If() ? bol : m2b);
}
}
}
_igvn.replace_node(check, C->top());
}
}
Expand Down
5 changes: 1 addition & 4 deletions src/java.base/share/classes/java/lang/invoke/VarHandles.java
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,7 @@ static VarHandle makeArrayElementHandle(Class<?> arrayClass) {
int ashift = 31 - Integer.numberOfLeadingZeros(ascale);

if (!componentType.isPrimitive()) {
// the redundant componentType.isPrimitiveValueType() check is
// there to minimize the performance impact to non-value array.
// It should be removed when Unsafe::isFlattenedArray is intrinsified.
return maybeAdapt(PrimitiveClass.isPrimitiveValueType(componentType) && UNSAFE.isFlattenedArray(arrayClass)
return maybeAdapt(UNSAFE.isFlattenedArray(arrayClass)
? new VarHandleValues.Array(aoffset, ashift, arrayClass)
: new VarHandleReferences.Array(aoffset, ashift, arrayClass));
}
Expand Down
1 change: 1 addition & 0 deletions src/java.base/share/classes/jdk/internal/misc/Unsafe.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ public boolean isFlattened(Field f) {
/**
* Returns true if the given class is a flattened array.
*/
@IntrinsicCandidate
public native boolean isFlattenedArray(Class<?> arrayClass);

/**
Expand Down
1 change: 0 additions & 1 deletion test/hotspot/jtreg/ProblemList.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ compiler/vectorapi/VectorLogicalOpIdentityTest.java 8302459 linux-x64,windows-x6

compiler/jvmci/TestUncaughtErrorInCompileMethod.java 8309073 generic-all

compiler/gcbarriers/TestZGCBarrierElision.java#ZGen 8313737 generic-all
#############################################################################

# :hotspot_gc
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -1659,4 +1659,38 @@ public void test80_verifier() throws Exception {
Field field = PrimitiveClass.asValueType(Test80Value1.class).getDeclaredField("v");
Asserts.assertEQ(test80(v, U.isFlattened(field), U.objectFieldOffset(field)), v.v);
}

// Test correctness of the Unsafe::isFlattenedArray intrinsic
@Test
public boolean test81(Class<?> cls) {
return U.isFlattenedArray(cls);
}

@Run(test = "test81")
public void test81_verifier() {
Asserts.assertEQ(test81(MyValue1[].class), TEST33_FLATTENED_ARRAY, "test81_1 failed");
Asserts.assertFalse(test81(String[].class), "test81_2 failed");
Asserts.assertFalse(test81(String.class), "test81_3 failed");
Asserts.assertFalse(test81(int[].class), "test81_4 failed");
}

// Verify that Unsafe::isFlattenedArray checks with statically known classes
// are folded
@Test
@IR(failOn = {LOADK})
public boolean test82() {
boolean check1 = U.isFlattenedArray(MyValue1[].class);
if (!TEST33_FLATTENED_ARRAY) {
check1 = !check1;
}
boolean check2 = !U.isFlattenedArray(String[].class);
boolean check3 = !U.isFlattenedArray(String.class);
boolean check4 = !U.isFlattenedArray(int[].class);
return check1 && check2 && check3 && check4;
}

@Run(test = "test82")
public void test82_verifier() {
Asserts.assertTrue(test82(), "test82 failed");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package org.openjdk.bench.valhalla.intrinsics;

import org.openjdk.jmh.annotations.*;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.TimeUnit;
import jdk.internal.misc.Unsafe;

@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Fork(value = 1,
jvmArgsAppend = {"--add-opens", "java.base/jdk.internal.misc=ALL-UNNAMED",
"-XX:+EnableValhalla", "-XX:+EnablePrimitiveClasses"})
@Warmup(iterations = 3, time = 1)
@Measurement(iterations = 5, time = 1)
public class IsFlattenedArray {

private static final Unsafe U = Unsafe.getUnsafe();
private static final VarHandle objectArrayVarHandle =
MethodHandles.arrayElementVarHandle(Object[].class);

@State(Scope.Benchmark)
public static class ClassState {
public Class flattenedArrayClass = Point[].class;
public Class nonFlattenedArrayClass = String[].class;

public Object[] objectArray = new Object[10];
public Object objectElement = new Object();
public int arrayIndex = 0;
}

@Benchmark
public boolean testKnownFlattenedClass() {
return U.isFlattenedArray(Point[].class);
}

@Benchmark
public boolean testKnownNonFlattenedClass() {
return U.isFlattenedArray(String[].class);
}

@Benchmark
public boolean testUnknownFlattenedClass(ClassState state) {
return U.isFlattenedArray(state.flattenedArrayClass);
}

@Benchmark
public boolean testUnknownNonFlattenedClass(ClassState state) {
return U.isFlattenedArray(state.nonFlattenedArrayClass);
}

@Benchmark
public void setArrayElement(ClassState state) {
objectArrayVarHandle.set(state.objectArray, state.arrayIndex, state.objectElement);
}

@Benchmark
public VarHandle makeArrayVarHandle() {
return MethodHandles.arrayElementVarHandle(Object[].class);
}

}

primitive class Point {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}

0 comments on commit 985474d

Please sign in to comment.