6849984: Value methods for platform dependent math functions constant fold incorrectly
Reviewed-by: kvn, twisti
--- a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp Wed Jan 13 23:05:52 2010 -0800
+++ b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp Fri Jan 15 11:53:33 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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
@@ -394,6 +394,11 @@
}
+bool AbstractInterpreter::can_be_compiled(methodHandle m) {
+ // No special entry points that preclude compilation
+ return true;
+}
+
// This method tells the deoptimizer how big an interpreted frame must be:
int AbstractInterpreter::size_activation(methodOop method,
int tempcount,
--- a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp Wed Jan 13 23:05:52 2010 -0800
+++ b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp Fri Jan 15 11:53:33 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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
@@ -2862,6 +2862,9 @@
// arraycopy stubs used by compilers
generate_arraycopy_stubs();
+
+ // Don't initialize the platform math functions since sparc
+ // doesn't have intrinsics for these operations.
}
--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp Wed Jan 13 23:05:52 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp Fri Jan 15 11:53:33 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1999-2010 Sun Microsystems, Inc. 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
@@ -2030,6 +2030,54 @@
entry_checkcast_arraycopy);
}
+ void generate_math_stubs() {
+ {
+ StubCodeMark mark(this, "StubRoutines", "log");
+ StubRoutines::_intrinsic_log = (double (*)(double)) __ pc();
+
+ __ fld_d(Address(rsp, 4));
+ __ flog();
+ __ ret(0);
+ }
+ {
+ StubCodeMark mark(this, "StubRoutines", "log10");
+ StubRoutines::_intrinsic_log10 = (double (*)(double)) __ pc();
+
+ __ fld_d(Address(rsp, 4));
+ __ flog10();
+ __ ret(0);
+ }
+ {
+ StubCodeMark mark(this, "StubRoutines", "sin");
+ StubRoutines::_intrinsic_sin = (double (*)(double)) __ pc();
+
+ __ fld_d(Address(rsp, 4));
+ __ trigfunc('s');
+ __ ret(0);
+ }
+ {
+ StubCodeMark mark(this, "StubRoutines", "cos");
+ StubRoutines::_intrinsic_cos = (double (*)(double)) __ pc();
+
+ __ fld_d(Address(rsp, 4));
+ __ trigfunc('c');
+ __ ret(0);
+ }
+ {
+ StubCodeMark mark(this, "StubRoutines", "tan");
+ StubRoutines::_intrinsic_tan = (double (*)(double)) __ pc();
+
+ __ fld_d(Address(rsp, 4));
+ __ trigfunc('t');
+ __ ret(0);
+ }
+
+ // The intrinsic version of these seem to return the same value as
+ // the strict version.
+ StubRoutines::_intrinsic_exp = SharedRuntime::dexp;
+ StubRoutines::_intrinsic_pow = SharedRuntime::dpow;
+ }
+
public:
// Information about frame layout at time of blocking runtime call.
// Note that we only have to preserve callee-saved registers since
@@ -2228,6 +2276,8 @@
MethodHandles::generate_method_handle_stub(_masm, ek);
}
}
+
+ generate_math_stubs();
}
--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp Wed Jan 13 23:05:52 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp Fri Jan 15 11:53:33 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2010 Sun Microsystems, Inc. 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
@@ -2731,6 +2731,79 @@
StubRoutines::_arrayof_oop_arraycopy = StubRoutines::_oop_arraycopy;
}
+ void generate_math_stubs() {
+ {
+ StubCodeMark mark(this, "StubRoutines", "log");
+ StubRoutines::_intrinsic_log = (double (*)(double)) __ pc();
+
+ __ subq(rsp, 8);
+ __ movdbl(Address(rsp, 0), xmm0);
+ __ fld_d(Address(rsp, 0));
+ __ flog();
+ __ fstp_d(Address(rsp, 0));
+ __ movdbl(xmm0, Address(rsp, 0));
+ __ addq(rsp, 8);
+ __ ret(0);
+ }
+ {
+ StubCodeMark mark(this, "StubRoutines", "log10");
+ StubRoutines::_intrinsic_log10 = (double (*)(double)) __ pc();
+
+ __ subq(rsp, 8);
+ __ movdbl(Address(rsp, 0), xmm0);
+ __ fld_d(Address(rsp, 0));
+ __ flog10();
+ __ fstp_d(Address(rsp, 0));
+ __ movdbl(xmm0, Address(rsp, 0));
+ __ addq(rsp, 8);
+ __ ret(0);
+ }
+ {
+ StubCodeMark mark(this, "StubRoutines", "sin");
+ StubRoutines::_intrinsic_sin = (double (*)(double)) __ pc();
+
+ __ subq(rsp, 8);
+ __ movdbl(Address(rsp, 0), xmm0);
+ __ fld_d(Address(rsp, 0));
+ __ trigfunc('s');
+ __ fstp_d(Address(rsp, 0));
+ __ movdbl(xmm0, Address(rsp, 0));
+ __ addq(rsp, 8);
+ __ ret(0);
+ }
+ {
+ StubCodeMark mark(this, "StubRoutines", "cos");
+ StubRoutines::_intrinsic_cos = (double (*)(double)) __ pc();
+
+ __ subq(rsp, 8);
+ __ movdbl(Address(rsp, 0), xmm0);
+ __ fld_d(Address(rsp, 0));
+ __ trigfunc('c');
+ __ fstp_d(Address(rsp, 0));
+ __ movdbl(xmm0, Address(rsp, 0));
+ __ addq(rsp, 8);
+ __ ret(0);
+ }
+ {
+ StubCodeMark mark(this, "StubRoutines", "tan");
+ StubRoutines::_intrinsic_tan = (double (*)(double)) __ pc();
+
+ __ subq(rsp, 8);
+ __ movdbl(Address(rsp, 0), xmm0);
+ __ fld_d(Address(rsp, 0));
+ __ trigfunc('t');
+ __ fstp_d(Address(rsp, 0));
+ __ movdbl(xmm0, Address(rsp, 0));
+ __ addq(rsp, 8);
+ __ ret(0);
+ }
+
+ // The intrinsic version of these seem to return the same value as
+ // the strict version.
+ StubRoutines::_intrinsic_exp = SharedRuntime::dexp;
+ StubRoutines::_intrinsic_pow = SharedRuntime::dpow;
+ }
+
#undef __
#define __ masm->
@@ -2945,6 +3018,8 @@
MethodHandles::generate_method_handle_stub(_masm, ek);
}
}
+
+ generate_math_stubs();
}
public:
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Wed Jan 13 23:05:52 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Fri Jan 15 11:53:33 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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
@@ -1431,6 +1431,23 @@
}
+// These should never be compiled since the interpreter will prefer
+// the compiled version to the intrinsic version.
+bool AbstractInterpreter::can_be_compiled(methodHandle m) {
+ switch (method_kind(m)) {
+ case Interpreter::java_lang_math_sin : // fall thru
+ case Interpreter::java_lang_math_cos : // fall thru
+ case Interpreter::java_lang_math_tan : // fall thru
+ case Interpreter::java_lang_math_abs : // fall thru
+ case Interpreter::java_lang_math_log : // fall thru
+ case Interpreter::java_lang_math_log10 : // fall thru
+ case Interpreter::java_lang_math_sqrt :
+ return false;
+ default:
+ return true;
+ }
+}
+
// How much stack a method activation needs in words.
int AbstractInterpreter::size_top_interpreter_activation(methodOop method) {
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Wed Jan 13 23:05:52 2010 -0800
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Fri Jan 15 11:53:33 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2010 Sun Microsystems, Inc. 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
@@ -1456,6 +1456,23 @@
generate_normal_entry(synchronized);
}
+// These should never be compiled since the interpreter will prefer
+// the compiled version to the intrinsic version.
+bool AbstractInterpreter::can_be_compiled(methodHandle m) {
+ switch (method_kind(m)) {
+ case Interpreter::java_lang_math_sin : // fall thru
+ case Interpreter::java_lang_math_cos : // fall thru
+ case Interpreter::java_lang_math_tan : // fall thru
+ case Interpreter::java_lang_math_abs : // fall thru
+ case Interpreter::java_lang_math_log : // fall thru
+ case Interpreter::java_lang_math_log10 : // fall thru
+ case Interpreter::java_lang_math_sqrt :
+ return false;
+ default:
+ return true;
+ }
+}
+
// How much stack a method activation needs in words.
int AbstractInterpreter::size_top_interpreter_activation(methodOop method) {
const int entry_size = frame::interpreter_frame_monitor_size();
--- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp Wed Jan 13 23:05:52 2010 -0800
+++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp Fri Jan 15 11:53:33 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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
@@ -109,6 +109,8 @@
static void print_method_kind(MethodKind kind) PRODUCT_RETURN;
+ static bool can_be_compiled(methodHandle m);
+
// Runtime support
// length = invoke bytecode length (to advance to next bytecode)
--- a/hotspot/src/share/vm/opto/subnode.cpp Wed Jan 13 23:05:52 2010 -0800
+++ b/hotspot/src/share/vm/opto/subnode.cpp Fri Jan 15 11:53:33 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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
@@ -1244,8 +1244,7 @@
if( t1 == Type::TOP ) return Type::TOP;
if( t1->base() != Type::DoubleCon ) return Type::DOUBLE;
double d = t1->getd();
- if( d < 0.0 ) return Type::DOUBLE;
- return TypeD::make( SharedRuntime::dcos( d ) );
+ return TypeD::make( StubRoutines::intrinsic_cos( d ) );
}
//=============================================================================
@@ -1256,8 +1255,7 @@
if( t1 == Type::TOP ) return Type::TOP;
if( t1->base() != Type::DoubleCon ) return Type::DOUBLE;
double d = t1->getd();
- if( d < 0.0 ) return Type::DOUBLE;
- return TypeD::make( SharedRuntime::dsin( d ) );
+ return TypeD::make( StubRoutines::intrinsic_sin( d ) );
}
//=============================================================================
@@ -1268,8 +1266,7 @@
if( t1 == Type::TOP ) return Type::TOP;
if( t1->base() != Type::DoubleCon ) return Type::DOUBLE;
double d = t1->getd();
- if( d < 0.0 ) return Type::DOUBLE;
- return TypeD::make( SharedRuntime::dtan( d ) );
+ return TypeD::make( StubRoutines::intrinsic_tan( d ) );
}
//=============================================================================
@@ -1280,8 +1277,7 @@
if( t1 == Type::TOP ) return Type::TOP;
if( t1->base() != Type::DoubleCon ) return Type::DOUBLE;
double d = t1->getd();
- if( d < 0.0 ) return Type::DOUBLE;
- return TypeD::make( SharedRuntime::dlog( d ) );
+ return TypeD::make( StubRoutines::intrinsic_log( d ) );
}
//=============================================================================
@@ -1292,8 +1288,7 @@
if( t1 == Type::TOP ) return Type::TOP;
if( t1->base() != Type::DoubleCon ) return Type::DOUBLE;
double d = t1->getd();
- if( d < 0.0 ) return Type::DOUBLE;
- return TypeD::make( SharedRuntime::dlog10( d ) );
+ return TypeD::make( StubRoutines::intrinsic_log10( d ) );
}
//=============================================================================
@@ -1304,8 +1299,7 @@
if( t1 == Type::TOP ) return Type::TOP;
if( t1->base() != Type::DoubleCon ) return Type::DOUBLE;
double d = t1->getd();
- if( d < 0.0 ) return Type::DOUBLE;
- return TypeD::make( SharedRuntime::dexp( d ) );
+ return TypeD::make( StubRoutines::intrinsic_exp( d ) );
}
@@ -1323,5 +1317,5 @@
double d2 = t2->getd();
if( d1 < 0.0 ) return Type::DOUBLE;
if( d2 < 0.0 ) return Type::DOUBLE;
- return TypeD::make( SharedRuntime::dpow( d1, d2 ) );
+ return TypeD::make( StubRoutines::intrinsic_pow( d1, d2 ) );
}
--- a/hotspot/src/share/vm/runtime/compilationPolicy.cpp Wed Jan 13 23:05:52 2010 -0800
+++ b/hotspot/src/share/vm/runtime/compilationPolicy.cpp Fri Jan 15 11:53:33 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2000-2010 Sun Microsystems, Inc. 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
@@ -74,6 +74,16 @@
if (m->is_abstract()) return false;
if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false;
+ // Math intrinsics should never be compiled as this can lead to
+ // monotonicity problems because the interpreter will prefer the
+ // compiled code to the intrinsic version. This can't happen in
+ // production because the invocation counter can't be incremented
+ // but we shouldn't expose the system to this problem in testing
+ // modes.
+ if (!AbstractInterpreter::can_be_compiled(m)) {
+ return false;
+ }
+
return !m->is_not_compilable();
}
--- a/hotspot/src/share/vm/runtime/stubRoutines.cpp Wed Jan 13 23:05:52 2010 -0800
+++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp Fri Jan 15 11:53:33 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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
@@ -97,6 +97,14 @@
address StubRoutines::_unsafe_arraycopy = NULL;
address StubRoutines::_generic_arraycopy = NULL;
+double (* StubRoutines::_intrinsic_log )(double) = NULL;
+double (* StubRoutines::_intrinsic_log10 )(double) = NULL;
+double (* StubRoutines::_intrinsic_exp )(double) = NULL;
+double (* StubRoutines::_intrinsic_pow )(double, double) = NULL;
+double (* StubRoutines::_intrinsic_sin )(double) = NULL;
+double (* StubRoutines::_intrinsic_cos )(double) = NULL;
+double (* StubRoutines::_intrinsic_tan )(double) = NULL;
+
// Initialization
//
// Note: to break cycle with universe initialization, stubs are generated in two phases.
--- a/hotspot/src/share/vm/runtime/stubRoutines.hpp Wed Jan 13 23:05:52 2010 -0800
+++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp Fri Jan 15 11:53:33 2010 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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
@@ -148,6 +148,20 @@
static address _unsafe_arraycopy;
static address _generic_arraycopy;
+ // These are versions of the java.lang.Math methods which perform
+ // the same operations as the intrinsic version. They are used for
+ // constant folding in the compiler to ensure equivalence. If the
+ // intrinsic version returns the same result as the strict version
+ // then they can be set to the appropriate function from
+ // SharedRuntime.
+ static double (*_intrinsic_log)(double);
+ static double (*_intrinsic_log10)(double);
+ static double (*_intrinsic_exp)(double);
+ static double (*_intrinsic_pow)(double, double);
+ static double (*_intrinsic_sin)(double);
+ static double (*_intrinsic_cos)(double);
+ static double (*_intrinsic_tan)(double);
+
public:
// Initialization/Testing
static void initialize1(); // must happen before universe::genesis
@@ -245,6 +259,35 @@
static address unsafe_arraycopy() { return _unsafe_arraycopy; }
static address generic_arraycopy() { return _generic_arraycopy; }
+ static double intrinsic_log(double d) {
+ assert(_intrinsic_log != NULL, "must be defined");
+ return _intrinsic_log(d);
+ }
+ static double intrinsic_log10(double d) {
+ assert(_intrinsic_log != NULL, "must be defined");
+ return _intrinsic_log10(d);
+ }
+ static double intrinsic_exp(double d) {
+ assert(_intrinsic_exp != NULL, "must be defined");
+ return _intrinsic_exp(d);
+ }
+ static double intrinsic_pow(double d, double d2) {
+ assert(_intrinsic_pow != NULL, "must be defined");
+ return _intrinsic_pow(d, d2);
+ }
+ static double intrinsic_sin(double d) {
+ assert(_intrinsic_sin != NULL, "must be defined");
+ return _intrinsic_sin(d);
+ }
+ static double intrinsic_cos(double d) {
+ assert(_intrinsic_cos != NULL, "must be defined");
+ return _intrinsic_cos(d);
+ }
+ static double intrinsic_tan(double d) {
+ assert(_intrinsic_tan != NULL, "must be defined");
+ return _intrinsic_tan(d);
+ }
+
//
// Default versions of the above arraycopy functions for platforms which do
// not have specialized versions