diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -1759,6 +1759,14 @@
emitOperandHelper(dst, src, 0);
}
+ public final void cmpb(Register dst, Register src) {
+ CMP.byteRmOp.emit(this, BYTE, dst, src);
+ }
+
+ public final void cmpw(Register dst, Register src) {
+ CMP.rmOp.emit(this, WORD, dst, src);
+ }
+
public final void cmpl(Register dst, int imm32) {
CMP.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java
@@ -374,6 +374,22 @@
"jdk/jfr/internal/JVM.getEventWriter()Ljava/lang/Object;");
}
+ if (isJDK12OrHigher()) {
+ add(toBeInvestigated,
+ "java/lang/CharacterDataLatin1.isDigit(I)Z",
+ "java/lang/CharacterDataLatin1.isLowerCase(I)Z",
+ "java/lang/CharacterDataLatin1.isUpperCase(I)Z",
+ "java/lang/CharacterDataLatin1.isWhitespace(I)Z");
+ }
+
+ if (isJDK13OrHigher()) {
+ add(toBeInvestigated,
+ "java/lang/Math.max(DD)D",
+ "java/lang/Math.max(FF)F",
+ "java/lang/Math.min(DD)D",
+ "java/lang/Math.min(FF)F");
+ }
+
if (!config.inlineNotify()) {
add(ignore, "java/lang/Object.notify()V");
}
@@ -534,6 +550,10 @@
return GraalServices.JAVA_SPECIFICATION_VERSION >= 12;
}
+ private static boolean isJDK13OrHigher() {
+ return GraalServices.JAVA_SPECIFICATION_VERSION >= 13;
+ }
+
public interface Refiner {
void refine(CheckGraalIntrinsics checker);
}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -309,8 +309,11 @@
public final int jvmAccWrittenFlags = getConstant("JVM_ACC_WRITTEN_FLAGS", Integer.class);
public final int jvmAccSynthetic = getConstant("JVM_ACC_SYNTHETIC", Integer.class);
+ public final int jvmciCompileStateCanPostOnExceptionsOffset = getFieldOffset("JVMCIEnv::_jvmti_can_post_on_exceptions", Integer.class, "jbyte", Integer.MIN_VALUE);
+
public final int threadTlabOffset = getFieldOffset("Thread::_tlab", Integer.class, "ThreadLocalAllocBuffer");
public final int javaThreadAnchorOffset = getFieldOffset("JavaThread::_anchor", Integer.class, "JavaFrameAnchor");
+ public final int javaThreadShouldPostOnExceptionsFlagOffset = getFieldOffset("JavaThread::_should_post_on_exceptions_flag", Integer.class, "int", Integer.MIN_VALUE);
public final int threadObjectOffset = getFieldOffset("JavaThread::_threadObj", Integer.class, "oop");
public final int osThreadOffset = getFieldOffset("JavaThread::_osthread", Integer.class, "OSThread*");
public final int threadIsMethodHandleReturnOffset = getFieldOffset("JavaThread::_is_method_handle_return", Integer.class, "int");
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
@@ -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
@@ -124,7 +124,7 @@
Plugins plugins = new Plugins(invocationPlugins);
NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes);
HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
- HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin);
+ HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin, config, wordTypes);
plugins.appendTypePlugin(nodePlugin);
plugins.appendNodePlugin(nodePlugin);
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java
@@ -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);
+ }
+ }
+ }
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -1106,7 +1106,11 @@
deopt.updateNodeSourcePosition(() -> createBytecodePosition());
}
+ /**
+ * @return the entry point to exception dispatch
+ */
private AbstractBeginNode handleException(ValueNode exceptionObject, int bci, boolean deoptimizeOnly) {
+ FixedWithNextNode currentLastInstr = lastInstr;
assert bci == BytecodeFrame.BEFORE_BCI || bci == bci() : "invalid bci";
debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, (profilingInfo == null ? "" : profilingInfo.getExceptionSeen(bci)));
@@ -1126,18 +1130,25 @@
dispatchState.setRethrowException(true);
}
this.controlFlowSplit = true;
- FixedWithNextNode finishedDispatch = finishInstruction(dispatchBegin, dispatchState);
+ FixedWithNextNode afterExceptionLoaded = finishInstruction(dispatchBegin, dispatchState);
if (deoptimizeOnly) {
DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
- dispatchBegin.setNext(BeginNode.begin(deoptimizeNode));
+ afterExceptionLoaded.setNext(BeginNode.begin(deoptimizeNode));
} else {
- createHandleExceptionTarget(finishedDispatch, bci, dispatchState);
- }
+ createHandleExceptionTarget(afterExceptionLoaded, bci, dispatchState);
+ }
+ assert currentLastInstr == lastInstr;
return dispatchBegin;
}
- protected void createHandleExceptionTarget(FixedWithNextNode finishedDispatch, int bci, FrameStateBuilder dispatchState) {
+ protected void createHandleExceptionTarget(FixedWithNextNode afterExceptionLoaded, int bci, FrameStateBuilder dispatchState) {
+ FixedWithNextNode afterInstrumentation = afterExceptionLoaded;
+ for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
+ afterInstrumentation = plugin.instrumentExceptionDispatch(graph, afterInstrumentation);
+ assert afterInstrumentation.next() == null : "exception dispatch instrumentation will be linked to dispatch block";
+ }
+
BciBlock dispatchBlock = currentBlock.exceptionDispatchBlock();
/*
* The exception dispatch block is always for the last bytecode of a block, so if we are not
@@ -1149,7 +1160,7 @@
}
FixedNode target = createTarget(dispatchBlock, dispatchState);
- finishedDispatch.setNext(target);
+ afterInstrumentation.setNext(target);
}
protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind kind) {
@@ -4195,7 +4206,6 @@
handleIllegalNewInstance(resolvedType);
return;
}
-
maybeEagerlyInitialize(resolvedType);
ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
@@ -4509,7 +4519,6 @@
}
ResolvedJavaType holder = resolvedField.getDeclaringClass();
- maybeEagerlyInitialize(holder);
ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin();
if (classInitializationPlugin != null) {
classInitializationPlugin.apply(this, holder, this::createCurrentFrameState);
@@ -4545,16 +4554,20 @@
private ResolvedJavaField resolveStaticFieldAccess(JavaField field, ValueNode value) {
if (field instanceof ResolvedJavaField) {
ResolvedJavaField resolvedField = (ResolvedJavaField) field;
- if (resolvedField.getDeclaringClass().isInitialized() || graphBuilderConfig.getPlugins().getClassInitializationPlugin() != null) {
+ ResolvedJavaType resolvedType = resolvedField.getDeclaringClass();
+ maybeEagerlyInitialize(resolvedType);
+
+ if (resolvedType.isInitialized() || graphBuilderConfig.getPlugins().getClassInitializationPlugin() != null) {
return resolvedField;
}
+
/*
* Static fields have initialization semantics but may be safely accessed under certain
* conditions while the class is being initialized. Executing in the clinit or init of
- * classes which are subtypes of the field holder are sure to be running in a context
- * where the access is safe.
+ * subclasses (but not implementers) of the field holder are sure to be running in a
+ * context where the access is safe.
*/
- if (resolvedField.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) {
+ if (!resolvedType.isInterface() && resolvedType.isAssignableFrom(method.getDeclaringClass())) {
if (method.isClassInitializer() || method.isConstructor()) {
return resolvedField;
}
@@ -4588,7 +4601,6 @@
ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin();
ResolvedJavaType holder = resolvedField.getDeclaringClass();
- maybeEagerlyInitialize(holder);
if (classInitializationPlugin != null) {
Supplier stateBefore = () -> {
JavaKind[] pushedSlotKinds = {field.getJavaKind()};
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 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
@@ -125,6 +125,14 @@
return kind == JavaKind.Char;
}
+ private JavaKind getComparisonKind() {
+ return findTwoConsecutive ? (byteMode(kind) ? JavaKind.Char : JavaKind.Int) : kind;
+ }
+
+ private AVXKind.AVXSize getVectorSize() {
+ return AVXKind.getDataSize(vectorKind);
+ }
+
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
Register arrayPtr = asRegister(arrayPtrValue);
@@ -159,9 +167,6 @@
Label retNotFound = new Label();
Label end = new Label();
- AVXKind.AVXSize vectorSize = AVXKind.getDataSize(vectorKind);
- int nVectors = nValues == 1 ? 4 : nValues == 2 ? 2 : 1;
-
// load array length
// important: this must be the first register manipulation, since arrayLengthValue is
// annotated with @Use
@@ -178,10 +183,10 @@
}
// fill comparison vector with copies of the search value
for (int i = 0; i < nValues; i++) {
- emitBroadcast(asm, findTwoConsecutive ? (byteMode(kind) ? JavaKind.Char : JavaKind.Int) : kind, vecCmp[i], vecArray[0], vectorSize);
+ emitBroadcast(asm, getComparisonKind(), vecCmp[i], vecArray[0], getVectorSize());
}
- emitArrayIndexOfChars(crb, asm, kind, vectorSize, result, slotsRemaining, searchValue, vecCmp, vecArray, cmpResult, retFound, retNotFound, vmPageSize, nValues, nVectors, findTwoConsecutive);
+ emitArrayIndexOfChars(crb, asm, result, slotsRemaining, searchValue, vecCmp, vecArray, cmpResult, retFound, retNotFound);
// return -1 (no match)
asm.bind(retNotFound);
@@ -197,7 +202,7 @@
asm.bind(end);
}
- private static void emitArrayIndexOfChars(CompilationResultBuilder crb, AMD64MacroAssembler asm, JavaKind kind, AVXKind.AVXSize vectorSize,
+ private void emitArrayIndexOfChars(CompilationResultBuilder crb, AMD64MacroAssembler asm,
Register arrayPtr,
Register slotsRemaining,
Register[] searchValue,
@@ -205,11 +210,10 @@
Register[] vecArray,
Register[] cmpResult,
Label retFound,
- Label retNotFound,
- int vmPageSize,
- int nValues,
- int nVectors,
- boolean findTwoCharPrefix) {
+ Label retNotFound) {
+ int nVectors = nValues == 1 ? 4 : nValues == 2 ? 2 : 1;
+ AVXKind.AVXSize vectorSize = getVectorSize();
+
Label bulkVectorLoop = new Label();
Label singleVectorLoop = new Label();
Label[] vectorFound = {
@@ -229,7 +233,7 @@
int bulkLoopCondition = bulkSize;
int[] vectorOffsets;
JavaKind vectorCompareKind = kind;
- if (findTwoCharPrefix) {
+ if (findTwoConsecutive) {
singleVectorLoopCondition++;
bulkLoopCondition++;
bulkSize /= 2;
@@ -274,7 +278,7 @@
emitAlign(crb, asm);
asm.bind(bulkVectorLoop);
// memory-aligned bulk comparison
- emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, nVectors, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, vectorFound, !findTwoCharPrefix);
+ emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, nVectors, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, vectorFound, !findTwoConsecutive);
// adjust number of array slots remaining
asm.subl(slotsRemaining, bulkSize);
// adjust array pointer
@@ -293,7 +297,7 @@
asm.cmpl(slotsRemaining, singleVectorLoopCondition);
asm.jcc(AMD64Assembler.ConditionFlag.Below, lessThanVectorSizeRemaining);
// compare
- emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, findTwoCharPrefix ? 2 : 1, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, vectorFound, false);
+ emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, findTwoConsecutive ? 2 : 1, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, vectorFound, false);
// adjust number of array slots remaining
asm.subl(slotsRemaining, arraySlotsPerVector);
// adjust array pointer
@@ -313,16 +317,16 @@
asm.movl(tmpArrayPtrLow, arrayPtr);
// check if pointer + vector size would cross the page boundary
asm.andl(tmpArrayPtrLow, (vmPageSize - 1));
- asm.cmpl(tmpArrayPtrLow, (vmPageSize - (findTwoCharPrefix ? bytesPerVector + kind.getByteCount() : bytesPerVector)));
+ asm.cmpl(tmpArrayPtrLow, (vmPageSize - (findTwoConsecutive ? bytesPerVector + kind.getByteCount() : bytesPerVector)));
// if the page boundary would be crossed, do byte/character-wise comparison instead.
asm.jccb(AMD64Assembler.ConditionFlag.Above, lessThanVectorSizeRemainingLoop);
Label[] overBoundsMatch = {new Label(), new Label()};
// otherwise, do a vector compare that reads beyond array bounds
- emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, findTwoCharPrefix ? 2 : 1, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, overBoundsMatch, false);
+ emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, findTwoConsecutive ? 2 : 1, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, overBoundsMatch, false);
// no match
asm.jmp(retNotFound);
- if (findTwoCharPrefix) {
+ if (findTwoConsecutive) {
Label overBoundsFinish = new Label();
asm.bind(overBoundsMatch[1]);
// get match offset of second result
@@ -348,14 +352,14 @@
}
// check if offset of matched value is greater than number of bytes remaining / out of array
// bounds
- if (findTwoCharPrefix) {
+ if (findTwoConsecutive) {
asm.decrementl(slotsRemaining);
}
asm.cmpl(cmpResult[0], slotsRemaining);
// match is out of bounds, return no match
asm.jcc(AMD64Assembler.ConditionFlag.GreaterEqual, retNotFound);
// adjust number of array slots remaining
- if (findTwoCharPrefix) {
+ if (findTwoConsecutive) {
asm.incrementl(slotsRemaining, 1);
}
asm.subl(slotsRemaining, cmpResult[0]);
@@ -365,17 +369,17 @@
// compare remaining slots in the array one-by-one
asm.bind(lessThanVectorSizeRemainingLoop);
// check if enough array slots remain
- asm.cmpl(slotsRemaining, findTwoCharPrefix ? 1 : 0);
+ asm.cmpl(slotsRemaining, findTwoConsecutive ? 1 : 0);
asm.jcc(AMD64Assembler.ConditionFlag.LessEqual, retNotFound);
// load char / byte
if (byteMode(kind)) {
- if (findTwoCharPrefix) {
+ if (findTwoConsecutive) {
asm.movzwl(cmpResult[0], new AMD64Address(arrayPtr));
} else {
asm.movzbl(cmpResult[0], new AMD64Address(arrayPtr));
}
} else {
- if (findTwoCharPrefix) {
+ if (findTwoConsecutive) {
asm.movl(cmpResult[0], new AMD64Address(arrayPtr));
} else {
asm.movzwl(cmpResult[0], new AMD64Address(arrayPtr));
@@ -383,7 +387,7 @@
}
// check for match
for (int i = 0; i < nValues; i++) {
- asm.cmpl(cmpResult[0], searchValue[i]);
+ emitCompareInst(asm, getComparisonKind(), cmpResult[0], searchValue[i]);
asm.jcc(AMD64Assembler.ConditionFlag.Equal, retFound);
}
// adjust number of array slots remaining
@@ -393,11 +397,11 @@
// continue loop
asm.jmpb(lessThanVectorSizeRemainingLoop);
- for (int i = 1; i < nVectors; i += (findTwoCharPrefix ? 2 : 1)) {
+ for (int i = 1; i < nVectors; i += (findTwoConsecutive ? 2 : 1)) {
emitVectorFoundWithOffset(asm, kind, vectorOffsets[i], arrayPtr, cmpResult[i], slotsRemaining, vectorFound[i], retFound);
}
- if (findTwoCharPrefix) {
+ if (findTwoConsecutive) {
asm.bind(vectorFound[2]);
asm.addq(arrayPtr, vectorOffsets[2]);
// adjust number of array slots remaining
@@ -626,6 +630,23 @@
}
}
+ private static void emitCompareInst(AMD64MacroAssembler asm, JavaKind kind, Register dst, Register src) {
+ switch (kind) {
+ case Byte:
+ asm.cmpb(dst, src);
+ break;
+ case Short:
+ case Char:
+ asm.cmpw(dst, src);
+ break;
+ case Int:
+ asm.cmpl(dst, src);
+ break;
+ default:
+ asm.cmpq(dst, src);
+ }
+ }
+
private static boolean supportsAVX2(LIRGeneratorTool tool) {
return supports(tool, CPUFeature.AVX2);
}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java
@@ -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,6 +24,9 @@
package org.graalvm.compiler.nodes.graphbuilderconf;
+import org.graalvm.compiler.graph.Node.ValueNumberable;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.extended.GuardingNode;
@@ -210,6 +213,23 @@
}
/**
+ * Allows this plugin to add nodes after the exception object has been loaded in the dispatch
+ * sequence. Note that a {@link StructuredGraph} is provided to this call instead of a
+ * {@link GraphBuilderContext} so that the caller has a guarantee that its current control flow
+ * insertion point is not changed by this call. This means nodes must be added to the graph with
+ * the appropriate method (e.g., {@link StructuredGraph#unique} for {@link ValueNumberable}
+ * nodes) and fixed nodes must be manually {@linkplain FixedWithNextNode#setNext added} as
+ * successors of {@code afterExceptionLoaded}.
+ *
+ * @param graph the graph being parsed
+ * @param afterExceptionLoaded the last fixed node after loading the exception
+ * @return the last fixed node after instrumentation
+ */
+ default FixedWithNextNode instrumentExceptionDispatch(StructuredGraph graph, FixedWithNextNode afterExceptionLoaded) {
+ return afterExceptionLoaded;
+ }
+
+ /**
* If the plugin {@link GraphBuilderContext#push pushes} a value with a different
* {@link JavaKind} than specified by the bytecode, it must override this method and return
* {@code true}. This disables assertion checking for value kinds.
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerExactExceptionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerExactExceptionTest.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerExactExceptionTest.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerExactExceptionTest.java
@@ -86,6 +86,64 @@
}
}
+ public void testIntegerExactOverflowWithoutUse1(int input) {
+ Math.addExact(intCounter, input);
+ }
+
+ public void testIntegerExactOverflowWithoutUse2(int input, boolean cond) {
+ if (cond) {
+ Math.addExact(intCounter, input);
+ } else {
+ intCounter = Math.addExact(intCounter, input);
+ }
+ }
+
+ public void testIntegerExactOverflowWithoutUse3() {
+ Math.addExact(Integer.MAX_VALUE, 1);
+ }
+
+ @Test
+ public void testIntegerExactWithoutUse1() throws InvalidInstalledCodeException {
+ ResolvedJavaMethod method = getResolvedJavaMethod("testIntegerExactOverflowWithoutUse1");
+ InstalledCode code = getCode(method);
+
+ boolean gotException = false;
+ try {
+ code.executeVarargs(this, Integer.MAX_VALUE);
+ } catch (ArithmeticException e) {
+ gotException = true;
+ }
+ assertTrue(gotException);
+ }
+
+ @Test
+ public void testIntegerExactWithoutUse2() throws InvalidInstalledCodeException {
+ ResolvedJavaMethod method = getResolvedJavaMethod("testIntegerExactOverflowWithoutUse2");
+ InstalledCode code = getCode(method);
+
+ boolean gotException = false;
+ try {
+ code.executeVarargs(this, Integer.MAX_VALUE, true);
+ } catch (ArithmeticException e) {
+ gotException = true;
+ }
+ assertTrue(gotException);
+ }
+
+ @Test
+ public void testIntegerExactWithoutUse3() throws InvalidInstalledCodeException {
+ ResolvedJavaMethod method = getResolvedJavaMethod("testIntegerExactOverflowWithoutUse3");
+ InstalledCode code = getCode(method);
+
+ boolean gotException = false;
+ try {
+ code.executeVarargs(this);
+ } catch (ArithmeticException e) {
+ gotException = true;
+ }
+ assertTrue(gotException);
+ }
+
static long longCounter = 10;
public void testLongExactOverflowSnippet(long input) {
@@ -138,4 +196,44 @@
assertTrue(code.isValid());
}
}
+
+ public void testLongExactOverflowWithoutUse1(long input) {
+ Math.addExact(longCounter, input);
}
+
+ public void testLongExactOverflowWithoutUse2(long input, boolean cond) {
+ if (cond) {
+ Math.addExact(longCounter, input);
+ } else {
+ longCounter = Math.addExact(longCounter, input);
+ }
+ }
+
+ @Test
+ public void testLongExactWithoutUse1() throws InvalidInstalledCodeException {
+ ResolvedJavaMethod method = getResolvedJavaMethod("testLongExactOverflowWithoutUse1");
+ InstalledCode code = getCode(method);
+
+ boolean gotException = false;
+ try {
+ code.executeVarargs(this, Long.MAX_VALUE);
+ } catch (ArithmeticException e) {
+ gotException = true;
+ }
+ assertTrue(gotException);
+ }
+
+ @Test
+ public void testLongExactWithoutUse2() throws InvalidInstalledCodeException {
+ ResolvedJavaMethod method = getResolvedJavaMethod("testLongExactOverflowWithoutUse2");
+ InstalledCode code = getCode(method);
+
+ boolean gotException = false;
+ try {
+ code.executeVarargs(this, Long.MAX_VALUE, true);
+ } catch (ArithmeticException e) {
+ gotException = true;
+ }
+ assertTrue(gotException);
+ }
+}
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerExactFoldTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerExactFoldTest.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerExactFoldTest.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerExactFoldTest.java
@@ -50,11 +50,13 @@
import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerExactArithmeticNode;
import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerExactArithmeticSplitNode;
import org.junit.Assert;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
+@Ignore
@RunWith(Parameterized.class)
public class IntegerExactFoldTest extends GraalCompilerTest {
private final long lowerBoundA;
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompressInflateTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompressInflateTest.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompressInflateTest.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompressInflateTest.java
@@ -299,7 +299,7 @@
TestMethods(String testmname, Class> javaclass, Class> intrinsicClass, String javamname, Class>... params) {
javamethod = getResolvedJavaMethod(javaclass, javamname, params);
testmethod = getResolvedJavaMethod(testmname);
- testgraph = testGraph(testmname, javamname);
+ testgraph = getReplacements().getIntrinsicGraph(javamethod, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext());
assertInGraph(testgraph, intrinsicClass);
assert javamethod != null;
diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java
@@ -49,7 +49,7 @@
private final List codeAttributes;
private static final int MAJOR_VERSION_JAVA_MIN = 51; // JDK7
- private static final int MAJOR_VERSION_JAVA_MAX = 56; // JDK12
+ private static final int MAJOR_VERSION_JAVA_MAX = 57; // JDK13
private static final int MAGIC = 0xCAFEBABE;
/**