--- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java 2019-01-18 21:34:31.000000000 +0100 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java 2019-01-18 21:34:31.000000000 +0100 @@ -1,5 +1,5 @@ /* - * 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 @@ -24,21 +24,41 @@ 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; @@ -47,23 +67,30 @@ 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: - *

- * {@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: + *

*/ 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 @@ -180,4 +207,58 @@ } 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); + } + } + } }