# HG changeset patch # User vlivanov # Date 1574785087 -10800 # Node ID f9905e7c96aa5a7d44c53ddb957ab7fc1541f1e1 # Parent 8375560db76b625f7284bcdb920557722f7fc634# Parent eb3e2a5c2bcd000175a7db79bc24797eb30a18ed Merge diff -r eb3e2a5c2bcd -r f9905e7c96aa src/hotspot/cpu/x86/x86_32.ad --- a/src/hotspot/cpu/x86/x86_32.ad Tue Nov 26 17:00:57 2019 +0100 +++ b/src/hotspot/cpu/x86/x86_32.ad Tue Nov 26 19:18:07 2019 +0300 @@ -3917,6 +3917,13 @@ interface(REG_INTER); %} +operand eDXRegP(eRegP reg) %{ + constraint(ALLOC_IN_RC(edx_reg)); + match(reg); + format %{ "EDX" %} + interface(REG_INTER); +%} + operand eSIRegP(eRegP reg) %{ constraint(ALLOC_IN_RC(esi_reg)); match(reg); @@ -8977,7 +8984,7 @@ %} ins_pipe(ialu_reg_reg); -%} +%} //----------Long Instructions------------------------------------------------ // Add Long Register with Register diff -r eb3e2a5c2bcd -r f9905e7c96aa src/hotspot/cpu/x86/x86_64.ad --- a/src/hotspot/cpu/x86/x86_64.ad Tue Nov 26 17:00:57 2019 +0100 +++ b/src/hotspot/cpu/x86/x86_64.ad Tue Nov 26 19:18:07 2019 +0300 @@ -267,6 +267,9 @@ // Singleton class for RSI pointer register reg_class ptr_rsi_reg(RSI, RSI_H); +// Singleton class for RBP pointer register +reg_class ptr_rbp_reg(RBP, RBP_H); + // Singleton class for RDI pointer register reg_class ptr_rdi_reg(RDI, RDI_H); @@ -3530,6 +3533,16 @@ interface(REG_INTER); %} +operand rbp_RegP() +%{ + constraint(ALLOC_IN_RC(ptr_rbp_reg)); + match(RegP); + match(rRegP); + + format %{ %} + interface(REG_INTER); +%} + // Used in rep stosq operand rdi_RegP() %{ diff -r eb3e2a5c2bcd -r f9905e7c96aa src/hotspot/share/adlc/adlparse.cpp --- a/src/hotspot/share/adlc/adlparse.cpp Tue Nov 26 17:00:57 2019 +0100 +++ b/src/hotspot/share/adlc/adlparse.cpp Tue Nov 26 19:18:07 2019 +0300 @@ -123,6 +123,7 @@ parse_err(SEMERR, "Did not declare 'register' definitions"); } regBlock->addSpillRegClass(); + regBlock->addDynamicRegClass(); // Done with parsing, check consistency. diff -r eb3e2a5c2bcd -r f9905e7c96aa src/hotspot/share/adlc/archDesc.cpp --- a/src/hotspot/share/adlc/archDesc.cpp Tue Nov 26 17:00:57 2019 +0100 +++ b/src/hotspot/share/adlc/archDesc.cpp Tue Nov 26 19:18:07 2019 +0300 @@ -245,12 +245,12 @@ // Construct chain rules build_chain_rule(op); - MatchRule &mrule = *op->_matrule; - Predicate *pred = op->_predicate; + MatchRule *mrule = op->_matrule; + Predicate *pred = op->_predicate; // Grab the machine type of the operand const char *rootOp = op->_ident; - mrule._machType = rootOp; + mrule->_machType = rootOp; // Check for special cases if (strcmp(rootOp,"Universe")==0) continue; @@ -271,10 +271,13 @@ // Find result type for match. const char *result = op->reduce_result(); - bool has_root = false; - // Construct a MatchList for this entry - buildMatchList(op->_matrule, result, rootOp, pred, cost); + // Construct a MatchList for this entry. + // Iterate over the list to enumerate all match cases for operands with multiple match rules. + for (; mrule != NULL; mrule = mrule->_next) { + mrule->_machType = rootOp; + buildMatchList(mrule, result, rootOp, pred, cost); + } } } @@ -805,6 +808,8 @@ return "RegMask::Empty"; } else if (strcmp(reg_class_name,"stack_slots")==0) { return "(Compile::current()->FIRST_STACK_mask())"; + } else if (strcmp(reg_class_name, "dynamic")==0) { + return "*_opnds[0]->in_RegMask(0)"; } else { char *rc_name = toUpper(reg_class_name); const char *mask = "_mask"; @@ -867,7 +872,7 @@ } // Instructions producing 'Universe' use RegMask::Empty - if( strcmp(result,"Universe")==0 ) { + if (strcmp(result,"Universe") == 0) { return "RegMask::Empty"; } diff -r eb3e2a5c2bcd -r f9905e7c96aa src/hotspot/share/adlc/formsopt.cpp --- a/src/hotspot/share/adlc/formsopt.cpp Tue Nov 26 17:00:57 2019 +0100 +++ b/src/hotspot/share/adlc/formsopt.cpp Tue Nov 26 19:18:07 2019 +0300 @@ -80,6 +80,15 @@ _regClass.Insert(rc_name,reg_class); } +// Called after parsing the Register block. Record the register class +// for operands which are overwritten after matching. +void RegisterForm::addDynamicRegClass() { + const char *rc_name = "dynamic"; + RegClass* reg_class = new RegClass(rc_name); + reg_class->set_stack_version(false); + _rclasses.addName(rc_name); + _regClass.Insert(rc_name,reg_class); +} // Provide iteration over all register definitions // in the order used by the register allocator diff -r eb3e2a5c2bcd -r f9905e7c96aa src/hotspot/share/adlc/formsopt.hpp --- a/src/hotspot/share/adlc/formsopt.hpp Tue Nov 26 17:00:57 2019 +0100 +++ b/src/hotspot/share/adlc/formsopt.hpp Tue Nov 26 19:18:07 2019 +0300 @@ -104,6 +104,7 @@ AllocClass *addAllocClass(char *allocName); void addSpillRegClass(); + void addDynamicRegClass(); // Provide iteration over all register definitions // in the order used by the register allocator diff -r eb3e2a5c2bcd -r f9905e7c96aa src/hotspot/share/adlc/output_c.cpp --- a/src/hotspot/share/adlc/output_c.cpp Tue Nov 26 17:00:57 2019 +0100 +++ b/src/hotspot/share/adlc/output_c.cpp Tue Nov 26 19:18:07 2019 +0300 @@ -2781,6 +2781,8 @@ // Return the sole RegMask. if (strcmp(first_reg_class, "stack_slots") == 0) { fprintf(fp," return &(Compile::current()->FIRST_STACK_mask());\n"); + } else if (strcmp(first_reg_class, "dynamic") == 0) { + fprintf(fp," return &RegMask::Empty;\n"); } else { const char* first_reg_class_to_upper = toUpper(first_reg_class); fprintf(fp," return &%s_mask();\n", first_reg_class_to_upper); diff -r eb3e2a5c2bcd -r f9905e7c96aa src/hotspot/share/opto/parse3.cpp --- a/src/hotspot/share/opto/parse3.cpp Tue Nov 26 17:00:57 2019 +0100 +++ b/src/hotspot/share/opto/parse3.cpp Tue Nov 26 19:18:07 2019 +0300 @@ -55,8 +55,9 @@ return; } - // Deoptimize on putfield writes to call site target field. - if (!is_get && field->is_call_site_target()) { + // Deoptimize on putfield writes to call site target field outside of CallSite ctor. + if (!is_get && field->is_call_site_target() && + !(method()->holder() == field_holder && method()->is_object_initializer())) { uncommon_trap(Deoptimization::Reason_unhandled, Deoptimization::Action_reinterpret, NULL, "put to call site target field"); diff -r eb3e2a5c2bcd -r f9905e7c96aa src/java.base/share/classes/java/lang/invoke/CallSite.java --- a/src/java.base/share/classes/java/lang/invoke/CallSite.java Tue Nov 26 17:00:57 2019 +0100 +++ b/src/java.base/share/classes/java/lang/invoke/CallSite.java Tue Nov 26 19:18:07 2019 +0300 @@ -87,9 +87,10 @@ abstract public class CallSite { - // The actual payload of this call site: + // The actual payload of this call site. + // Can be modified using {@link MethodHandleNatives#setCallSiteTargetNormal} or {@link MethodHandleNatives#setCallSiteTargetVolatile}. /*package-private*/ - MethodHandle target; // Note: This field is known to the JVM. Do not change. + final MethodHandle target; // Note: This field is known to the JVM. /** * Make a blank call site object with the given method type. @@ -129,11 +130,11 @@ */ /*package-private*/ CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable { - this(targetType); + this(targetType); // need to initialize target to make CallSite.type() work in createTargetHook ConstantCallSite selfCCS = (ConstantCallSite) this; MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS); - checkTargetChange(this.target, boundTarget); - this.target = boundTarget; + setTargetNormal(boundTarget); // ConstantCallSite doesn't publish CallSite.target + UNSAFE.storeStoreFence(); // barrier between target and isFrozen updates } /** @@ -190,11 +191,12 @@ */ public abstract void setTarget(MethodHandle newTarget); - void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) { - MethodType oldType = oldTarget.type(); + private void checkTargetChange(MethodHandle newTarget) { + MethodType oldType = target.type(); // target is always present MethodType newType = newTarget.type(); // null check! - if (!newType.equals(oldType)) + if (newType != oldType) { throw wrongTargetType(newTarget, oldType); + } } private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) { @@ -217,7 +219,7 @@ */ public abstract MethodHandle dynamicInvoker(); - /*non-public*/ + /*package-private*/ MethodHandle makeDynamicInvoker() { MethodHandle getTarget = getTargetHandle().bindArgumentL(0, this); MethodHandle invoker = MethodHandles.exactInvoker(this.type()); @@ -283,19 +285,24 @@ } /*package-private*/ - void setTargetNormal(MethodHandle newTarget) { + final void setTargetNormal(MethodHandle newTarget) { + checkTargetChange(newTarget); MethodHandleNatives.setCallSiteTargetNormal(this, newTarget); } + /*package-private*/ - MethodHandle getTargetVolatile() { + final MethodHandle getTargetVolatile() { return (MethodHandle) UNSAFE.getReferenceVolatile(this, getTargetOffset()); } + /*package-private*/ - void setTargetVolatile(MethodHandle newTarget) { + final void setTargetVolatile(MethodHandle newTarget) { + checkTargetChange(newTarget); MethodHandleNatives.setCallSiteTargetVolatile(this, newTarget); } // this implements the upcall from the JVM, MethodHandleNatives.linkCallSite: + /*package-private*/ static CallSite makeSite(MethodHandle bootstrapMethod, // Callee information: String name, MethodType type, diff -r eb3e2a5c2bcd -r f9905e7c96aa src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java --- a/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java Tue Nov 26 17:00:57 2019 +0100 +++ b/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java Tue Nov 26 19:18:07 2019 +0300 @@ -25,6 +25,9 @@ package java.lang.invoke; +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.Stable; + /** * A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed. * An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently @@ -33,7 +36,10 @@ * @since 1.7 */ public class ConstantCallSite extends CallSite { - private final boolean isFrozen; + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + @Stable // should NOT be constant folded during instance initialization (isFrozen == false) + /*final*/ private boolean isFrozen; /** * Creates a call site with a permanent target. @@ -43,6 +49,7 @@ public ConstantCallSite(MethodHandle target) { super(target); isFrozen = true; + UNSAFE.storeStoreFence(); // properly publish isFrozen update } /** @@ -79,8 +86,9 @@ * @throws Throwable anything else thrown by the hook function */ protected ConstantCallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable { - super(targetType, createTargetHook); + super(targetType, createTargetHook); // "this" instance leaks into createTargetHook isFrozen = true; + UNSAFE.storeStoreFence(); // properly publish isFrozen } /** diff -r eb3e2a5c2bcd -r f9905e7c96aa src/java.base/share/classes/java/lang/invoke/MutableCallSite.java --- a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java Tue Nov 26 17:00:57 2019 +0100 +++ b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java Tue Nov 26 19:18:07 2019 +0300 @@ -152,7 +152,6 @@ * @see #getTarget */ @Override public void setTarget(MethodHandle newTarget) { - checkTargetChange(this.target, newTarget); setTargetNormal(newTarget); } diff -r eb3e2a5c2bcd -r f9905e7c96aa src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java --- a/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java Tue Nov 26 17:00:57 2019 +0100 +++ b/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java Tue Nov 26 19:18:07 2019 +0300 @@ -96,7 +96,6 @@ * @see #getTarget */ @Override public void setTarget(MethodHandle newTarget) { - checkTargetChange(getTargetVolatile(), newTarget); setTargetVolatile(newTarget); } diff -r eb3e2a5c2bcd -r f9905e7c96aa test/jdk/java/lang/invoke/CallSiteTest.java --- a/test/jdk/java/lang/invoke/CallSiteTest.java Tue Nov 26 17:00:57 2019 +0100 +++ b/test/jdk/java/lang/invoke/CallSiteTest.java Tue Nov 26 19:18:07 2019 +0300 @@ -24,10 +24,11 @@ /** * @test * @summary smoke tests for CallSite + * @library /test/lib * * @build indify.Indify * @compile CallSiteTest.java - * @run main/othervm/timeout=3600 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies + * @run main/othervm/timeout=3600 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -Xbatch * indify.Indify * --expand-properties --classpath ${test.classes} * --java test.java.lang.invoke.CallSiteTest @@ -40,6 +41,7 @@ import java.lang.invoke.*; import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; +import static jdk.test.lib.Asserts.*; public class CallSiteTest { private static final Class CLASS = CallSiteTest.class; @@ -51,16 +53,19 @@ static { try { + mh_foo = lookup().findStatic(CLASS, "foo", methodType(int.class, int.class, int.class)); mh_bar = lookup().findStatic(CLASS, "bar", methodType(int.class, int.class, int.class)); mcs = new MutableCallSite(mh_foo); vcs = new VolatileCallSite(mh_foo); } catch (Exception e) { e.printStackTrace(); + throw new Error(e); } } public static void main(String... av) throws Throwable { + testConstantCallSite(); testMutableCallSite(); testVolatileCallSite(); } @@ -69,9 +74,61 @@ private static final int RESULT1 = 762786192; private static final int RESULT2 = -21474836; - private static void assertEquals(int expected, int actual) { - if (expected != actual) - throw new AssertionError("expected: " + expected + ", actual: " + actual); + static final CallSite MCS = new MutableCallSite(methodType(void.class)); + static final MethodHandle MCS_INVOKER = MCS.dynamicInvoker(); + + static void test(boolean shouldThrow) { + try { + MCS_INVOKER.invokeExact(); + if (shouldThrow) { + throw new AssertionError("should throw"); + } + } catch (IllegalStateException ise) { + if (!shouldThrow) { + throw new AssertionError("should not throw", ise); + } + } catch (Throwable e) { + throw new Error(e); + } + } + + static class MyCCS extends ConstantCallSite { + public MyCCS(MethodType targetType, MethodHandle createTargetHook) throws Throwable { + super(targetType, createTargetHook); + } + } + + private static MethodHandle testConstantCallSiteHandler(CallSite cs, CallSite[] holder) throws Throwable { + holder[0] = cs; // capture call site instance for subsequent checks + + MethodType csType = cs.type(); // should not throw on partially constructed instance + + // Truly dynamic invoker for constant call site + MethodHandle getTarget = lookup().findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)) + .bindTo(cs); + MethodHandle invoker = MethodHandles.exactInvoker(csType); + MethodHandle target = MethodHandles.foldArguments(invoker, getTarget); + + MCS.setTarget(target); + // warmup + for (int i = 0; i < 20_000; i++) { + test(true); // should throw IllegalStateException + } + + return MethodHandles.empty(csType); // initialize cs with an empty method handle + } + + private static void testConstantCallSite() throws Throwable { + CallSite[] holder = new CallSite[1]; + MethodHandle handler = lookup().findStatic(CLASS, "testConstantCallSiteHandler", MethodType.methodType(MethodHandle.class, CallSite.class, CallSite[].class)); + handler = MethodHandles.insertArguments(handler, 1, new Object[] { holder } ); + + CallSite ccs = new MyCCS(MCS.type(), handler); // trigger call to handler + + if (ccs != holder[0]) { + throw new AssertionError("different call site instances"); + } + test(false); // should not throw } private static void testMutableCallSite() throws Throwable { @@ -83,11 +140,11 @@ for (int n = 0; n < 2; n++) { mcs.setTarget(mh_foo); for (int i = 0; i < 5; i++) { - assertEquals(RESULT1, runMutableCallSite()); + assertEQ(RESULT1, runMutableCallSite()); } mcs.setTarget(mh_bar); for (int i = 0; i < 5; i++) { - assertEquals(RESULT2, runMutableCallSite()); + assertEQ(RESULT2, runMutableCallSite()); } } } @@ -100,11 +157,11 @@ for (int n = 0; n < 2; n++) { vcs.setTarget(mh_foo); for (int i = 0; i < 5; i++) { - assertEquals(RESULT1, runVolatileCallSite()); + assertEQ(RESULT1, runVolatileCallSite()); } vcs.setTarget(mh_bar); for (int i = 0; i < 5; i++) { - assertEquals(RESULT2, runVolatileCallSite()); + assertEQ(RESULT2, runVolatileCallSite()); } } }