< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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.

@@ -22,50 +22,77 @@
  */
 
 
 package org.graalvm.compiler.hotspot.meta;
 
+import static jdk.vm.ci.meta.DeoptimizationAction.None;
+import static jdk.vm.ci.meta.DeoptimizationReason.TransferToInterpreter;
 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
 
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotCompilationIdentifier;
+import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
+import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
 import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.TypePlugin;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
 import org.graalvm.compiler.nodes.util.ConstantFoldUtil;
 import org.graalvm.compiler.word.Word;
 import org.graalvm.compiler.word.WordOperationPlugin;
+import jdk.internal.vm.compiler.word.LocationIdentity;
 
+import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.JavaTypeProfile;
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
+import java.lang.reflect.Field;
+import sun.misc.Unsafe;
+
 /**
- * This plugin handles the HotSpot-specific customizations of bytecode parsing:
- * <p>
- * {@link Word}-type rewriting for {@link GraphBuilderContext#parsingIntrinsic intrinsic} functions
- * (snippets and method substitutions), by forwarding to the {@link WordOperationPlugin}. Note that
- * we forward the {@link NodePlugin} and {@link TypePlugin} methods, but not the
+ * This plugin does HotSpot-specific customization of bytecode parsing:
+ * <ul>
+ * <li>{@link Word}-type rewriting for {@link GraphBuilderContext#parsingIntrinsic intrinsic}
+ * functions (snippets and method substitutions), by forwarding to the {@link WordOperationPlugin}.
+ * Note that we forward the {@link NodePlugin} and {@link TypePlugin} methods, but not the
  * {@link InlineInvokePlugin} methods implemented by {@link WordOperationPlugin}. The latter is not
  * necessary because HotSpot only uses the {@link Word} type in methods that are force-inlined,
- * i.e., there are never non-inlined invokes that involve the {@link Word} type.
- * <p>
- * Constant folding of field loads.
+ * i.e., there are never non-inlined invokes that involve the {@link Word} type.</li>
+ * <li>Constant folding of field loads.</li>
+ * </ul>
  */
 public final class HotSpotNodePlugin implements NodePlugin, TypePlugin {
     protected final WordOperationPlugin wordOperationPlugin;
+    private final GraalHotSpotVMConfig config;
+    private final HotSpotWordTypes wordTypes;
 
-    public HotSpotNodePlugin(WordOperationPlugin wordOperationPlugin) {
+    public HotSpotNodePlugin(WordOperationPlugin wordOperationPlugin, GraalHotSpotVMConfig config, HotSpotWordTypes wordTypes) {
         this.wordOperationPlugin = wordOperationPlugin;
+        this.config = config;
+        this.wordTypes = wordTypes;
     }
 
     @Override
     public boolean canChangeStackKind(GraphBuilderContext b) {
         if (b.parsingIntrinsic()) {

@@ -178,6 +205,60 @@
         if (b.parsingIntrinsic() && wordOperationPlugin.handleInstanceOf(b, object, type, profile)) {
             return true;
         }
         return false;
     }
+
+    @Override
+    public FixedWithNextNode instrumentExceptionDispatch(StructuredGraph graph, FixedWithNextNode afterExceptionLoaded) {
+        CompilationIdentifier id = graph.compilationId();
+        if (id instanceof HotSpotCompilationIdentifier) {
+            HotSpotCompilationRequest request = ((HotSpotCompilationIdentifier) id).getRequest();
+            if (request != null) {
+                long compileState = request.getJvmciEnv();
+                if (compileState != 0 &&
+                                config.jvmciCompileStateCanPostOnExceptionsOffset != Integer.MIN_VALUE &&
+                                config.javaThreadShouldPostOnExceptionsFlagOffset != Integer.MIN_VALUE) {
+                    long canPostOnExceptionsOffset = compileState + config.jvmciCompileStateCanPostOnExceptionsOffset;
+                    boolean canPostOnExceptions = UNSAFE.getByte(canPostOnExceptionsOffset) != 0;
+                    if (canPostOnExceptions) {
+                        // If the exception capability is set, then generate code
+                        // to check the JavaThread.should_post_on_exceptions flag to see
+                        // if we actually need to report exception events for the current
+                        // thread. If not, take the fast path otherwise deoptimize.
+                        CurrentJavaThreadNode thread = graph.unique(new CurrentJavaThreadNode(wordTypes.getWordKind()));
+                        ValueNode offset = graph.unique(ConstantNode.forLong(config.javaThreadShouldPostOnExceptionsFlagOffset));
+                        AddressNode address = graph.unique(new OffsetAddressNode(thread, offset));
+                        ReadNode shouldPostException = graph.add(new ReadNode(address, JAVA_THREAD_SHOULD_POST_ON_EXCEPTIONS_FLAG_LOCATION, StampFactory.intValue(), BarrierType.NONE));
+                        afterExceptionLoaded.setNext(shouldPostException);
+                        ValueNode zero = graph.unique(ConstantNode.forInt(0));
+                        LogicNode cond = graph.unique(new IntegerEqualsNode(shouldPostException, zero));
+                        FixedGuardNode check = graph.add(new FixedGuardNode(cond, TransferToInterpreter, None, false));
+                        shouldPostException.setNext(check);
+                        return check;
+                    }
+                }
+            }
+        }
+        return afterExceptionLoaded;
+    }
+
+    private static final LocationIdentity JAVA_THREAD_SHOULD_POST_ON_EXCEPTIONS_FLAG_LOCATION = NamedLocationIdentity.mutable("JavaThread::_should_post_on_exceptions_flag");
+
+    private static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            // Fast path when we are trusted.
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            // Slow path when we are not trusted.
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
 }
< prev index next >