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; /**