Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8150669: C1 intrinsic for Class.isPrimitive #37

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 12 additions & 1 deletion hotspot/src/share/vm/c1/c1_Canonicalizer.cpp
Expand Up @@ -463,7 +463,7 @@ void Canonicalizer::do_Intrinsic (Intrinsic* x) {
InstanceConstant* c = x->argument_at(0)->type()->as_InstanceConstant();
if (c != NULL && !c->value()->is_null_object()) {
// ciInstance::java_mirror_type() returns non-NULL only for Java mirrors
ciType* t = c->value()->as_instance()->java_mirror_type();
ciType* t = c->value()->java_mirror_type();
if (t->is_klass()) {
// substitute cls.isInstance(obj) of a constant Class into
// an InstantOf instruction
Expand All @@ -479,6 +479,17 @@ void Canonicalizer::do_Intrinsic (Intrinsic* x) {
}
break;
}
case vmIntrinsics::_isPrimitive : {
assert(x->number_of_arguments() == 1, "wrong type");

// Class.isPrimitive is known on constant classes:
InstanceConstant* c = x->argument_at(0)->type()->as_InstanceConstant();
if (c != NULL && !c->value()->is_null_object()) {
ciType* t = c->value()->java_mirror_type();
set_constant(t->is_primitive_type());
}
break;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
Expand Up @@ -3514,6 +3514,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {

case vmIntrinsics::_getClass :
case vmIntrinsics::_isInstance :
case vmIntrinsics::_isPrimitive :
if (!InlineClassNatives) return false;
preserves_state = true;
break;
Expand Down
19 changes: 19 additions & 0 deletions hotspot/src/share/vm/c1/c1_LIRGenerator.cpp
Expand Up @@ -1290,6 +1290,24 @@ void LIRGenerator::do_getClass(Intrinsic* x) {
__ move_wide(new LIR_Address(temp, in_bytes(Klass::java_mirror_offset()), T_OBJECT), result);
}

// java.lang.Class::isPrimitive()
void LIRGenerator::do_isPrimitive(Intrinsic* x) {
assert(x->number_of_arguments() == 1, "wrong type");

LIRItem rcvr(x->argument_at(0), this);
rcvr.load_item();
LIR_Opr temp = new_register(T_METADATA);
LIR_Opr result = rlock_result(x);

CodeEmitInfo* info = NULL;
if (x->needs_null_check()) {
info = state_for(x);
}

__ move(new LIR_Address(rcvr.result(), java_lang_Class::klass_offset_in_bytes(), T_ADDRESS), temp, info);
__ cmp(lir_cond_notEqual, temp, LIR_OprFact::intConst(0));
__ cmove(lir_cond_notEqual, LIR_OprFact::intConst(0), LIR_OprFact::intConst(1), result, T_BOOLEAN);
}

// Example: Thread.currentThread()
void LIRGenerator::do_currentThread(Intrinsic* x) {
Expand Down Expand Up @@ -3187,6 +3205,7 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {

case vmIntrinsics::_Object_init: do_RegisterFinalizer(x); break;
case vmIntrinsics::_isInstance: do_isInstance(x); break;
case vmIntrinsics::_isPrimitive: do_isPrimitive(x); break;
case vmIntrinsics::_getClass: do_getClass(x); break;
case vmIntrinsics::_currentThread: do_currentThread(x); break;

Expand Down
1 change: 1 addition & 0 deletions hotspot/src/share/vm/c1/c1_LIRGenerator.hpp
Expand Up @@ -242,6 +242,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {

void do_RegisterFinalizer(Intrinsic* x);
void do_isInstance(Intrinsic* x);
void do_isPrimitive(Intrinsic* x);
void do_getClass(Intrinsic* x);
void do_currentThread(Intrinsic* x);
void do_MathIntrinsic(Intrinsic* x);
Expand Down
165 changes: 165 additions & 0 deletions hotspot/test/compiler/intrinsics/klass/TestIsPrimitive.java
@@ -0,0 +1,165 @@
/*
* Copyright (c) 2016, 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.
*/

/*
* @test
* @bug 8150669
* @summary C1 intrinsic for Class.isPrimitive
*
* @run main/othervm -ea -Diters=200 -Xint TestIsPrimitive
* @run main/othervm -ea -Diters=30000 -XX:TieredStopAtLevel=1 TestIsPrimitive
* @run main/othervm -ea -Diters=30000 -XX:TieredStopAtLevel=4 TestIsPrimitive
*/
import java.lang.reflect.Field;
import java.lang.reflect.Array;
import java.util.concurrent.Callable;

public class TestIsPrimitive {
static final int ITERS = Integer.getInteger("iters", 1);

public static void main(String... args) throws Exception {
testOK(true, InlineConstants::testBoolean);
testOK(true, InlineConstants::testByte);
testOK(true, InlineConstants::testShort);
testOK(true, InlineConstants::testChar);
testOK(true, InlineConstants::testInt);
testOK(true, InlineConstants::testFloat);
testOK(true, InlineConstants::testLong);
testOK(true, InlineConstants::testDouble);
testOK(false, InlineConstants::testObject);
testOK(false, InlineConstants::testArray);

testOK(true, StaticConstants::testBoolean);
testOK(true, StaticConstants::testByte);
testOK(true, StaticConstants::testShort);
testOK(true, StaticConstants::testChar);
testOK(true, StaticConstants::testInt);
testOK(true, StaticConstants::testFloat);
testOK(true, StaticConstants::testLong);
testOK(true, StaticConstants::testDouble);
testOK(false, StaticConstants::testObject);
testOK(false, StaticConstants::testArray);
testNPE( StaticConstants::testNull);

testOK(true, NoConstants::testBoolean);
testOK(true, NoConstants::testByte);
testOK(true, NoConstants::testShort);
testOK(true, NoConstants::testChar);
testOK(true, NoConstants::testInt);
testOK(true, NoConstants::testFloat);
testOK(true, NoConstants::testLong);
testOK(true, NoConstants::testDouble);
testOK(false, NoConstants::testObject);
testOK(false, NoConstants::testArray);
testNPE( NoConstants::testNull);
}

public static void testOK(boolean expected, Callable<Object> test) throws Exception {
for (int c = 0; c < ITERS; c++) {
Object res = test.call();
if (!res.equals(expected)) {
throw new IllegalStateException("Wrong result: expected = " + expected + ", but got " + res);
}
}
}

static volatile Object sink;

public static void testNPE(Callable<Object> test) throws Exception {
for (int c = 0; c < ITERS; c++) {
try {
sink = test.call();
throw new IllegalStateException("Expected NPE");
} catch (NullPointerException iae) {
// expected
}
}
}

static volatile Class<?> classBoolean = boolean.class;
static volatile Class<?> classByte = byte.class;
static volatile Class<?> classShort = short.class;
static volatile Class<?> classChar = char.class;
static volatile Class<?> classInt = int.class;
static volatile Class<?> classFloat = float.class;
static volatile Class<?> classLong = long.class;
static volatile Class<?> classDouble = double.class;
static volatile Class<?> classObject = Object.class;
static volatile Class<?> classArray = Object[].class;
static volatile Class<?> classNull = null;

static final Class<?> staticClassBoolean = boolean.class;
static final Class<?> staticClassByte = byte.class;
static final Class<?> staticClassShort = short.class;
static final Class<?> staticClassChar = char.class;
static final Class<?> staticClassInt = int.class;
static final Class<?> staticClassFloat = float.class;
static final Class<?> staticClassLong = long.class;
static final Class<?> staticClassDouble = double.class;
static final Class<?> staticClassObject = Object.class;
static final Class<?> staticClassArray = Object[].class;
static final Class<?> staticClassNull = null;

static class InlineConstants {
static boolean testBoolean() { return boolean.class.isPrimitive(); }
static boolean testByte() { return byte.class.isPrimitive(); }
static boolean testShort() { return short.class.isPrimitive(); }
static boolean testChar() { return char.class.isPrimitive(); }
static boolean testInt() { return int.class.isPrimitive(); }
static boolean testFloat() { return float.class.isPrimitive(); }
static boolean testLong() { return long.class.isPrimitive(); }
static boolean testDouble() { return double.class.isPrimitive(); }
static boolean testObject() { return Object.class.isPrimitive(); }
static boolean testArray() { return Object[].class.isPrimitive(); }
}

static class StaticConstants {
static boolean testBoolean() { return staticClassBoolean.isPrimitive(); }
static boolean testByte() { return staticClassByte.isPrimitive(); }
static boolean testShort() { return staticClassShort.isPrimitive(); }
static boolean testChar() { return staticClassChar.isPrimitive(); }
static boolean testInt() { return staticClassInt.isPrimitive(); }
static boolean testFloat() { return staticClassFloat.isPrimitive(); }
static boolean testLong() { return staticClassLong.isPrimitive(); }
static boolean testDouble() { return staticClassDouble.isPrimitive(); }
static boolean testObject() { return staticClassObject.isPrimitive(); }
static boolean testArray() { return staticClassArray.isPrimitive(); }
static boolean testNull() { return staticClassNull.isPrimitive(); }
}

static class NoConstants {
static boolean testBoolean() { return classBoolean.isPrimitive(); }
static boolean testByte() { return classByte.isPrimitive(); }
static boolean testShort() { return classShort.isPrimitive(); }
static boolean testChar() { return classChar.isPrimitive(); }
static boolean testInt() { return classInt.isPrimitive(); }
static boolean testFloat() { return classFloat.isPrimitive(); }
static boolean testLong() { return classLong.isPrimitive(); }
static boolean testDouble() { return classDouble.isPrimitive(); }
static boolean testObject() { return classObject.isPrimitive(); }
static boolean testArray() { return classArray.isPrimitive(); }
static boolean testNull() { return classNull.isPrimitive(); }
}

}