branch | datagramsocketimpl-branch |
changeset 58678 | 9cf78a70fa4f |
parent 54601 | c40b2a190173 |
child 58679 | 9c3209ff7550 |
58677:13588c901957 | 58678:9cf78a70fa4f |
---|---|
33 import static jdk.vm.ci.meta.DeoptimizationAction.None; |
33 import static jdk.vm.ci.meta.DeoptimizationAction.None; |
34 import static jdk.vm.ci.meta.DeoptimizationReason.ClassCastException; |
34 import static jdk.vm.ci.meta.DeoptimizationReason.ClassCastException; |
35 import static jdk.vm.ci.meta.DeoptimizationReason.JavaSubroutineMismatch; |
35 import static jdk.vm.ci.meta.DeoptimizationReason.JavaSubroutineMismatch; |
36 import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException; |
36 import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException; |
37 import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint; |
37 import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint; |
38 import static jdk.vm.ci.meta.DeoptimizationReason.TypeCheckedInliningViolated; |
|
39 import static jdk.vm.ci.meta.DeoptimizationReason.UnreachedCode; |
38 import static jdk.vm.ci.meta.DeoptimizationReason.UnreachedCode; |
40 import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved; |
39 import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved; |
41 import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI; |
40 import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI; |
42 import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; |
41 import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; |
43 import static org.graalvm.compiler.bytecode.Bytecodes.AALOAD; |
42 import static org.graalvm.compiler.bytecode.Bytecodes.AALOAD; |
254 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; |
253 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; |
255 import static org.graalvm.compiler.java.BytecodeParserOptions.InlinePartialIntrinsicExitDuringParsing; |
254 import static org.graalvm.compiler.java.BytecodeParserOptions.InlinePartialIntrinsicExitDuringParsing; |
256 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceBytecodeParserLevel; |
255 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceBytecodeParserLevel; |
257 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceInlineDuringParsing; |
256 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceInlineDuringParsing; |
258 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceParserPlugins; |
257 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceParserPlugins; |
259 import static org.graalvm.compiler.java.BytecodeParserOptions.UseGuardedIntrinsics; |
|
260 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY; |
|
261 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LUDICROUSLY_FAST_PATH_PROBABILITY; |
258 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LUDICROUSLY_FAST_PATH_PROBABILITY; |
262 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LUDICROUSLY_SLOW_PATH_PROBABILITY; |
259 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LUDICROUSLY_SLOW_PATH_PROBABILITY; |
263 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_DURING_PARSING; |
260 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_DURING_PARSING; |
264 import static org.graalvm.compiler.nodes.type.StampTool.isPointerNonNull; |
261 import static org.graalvm.compiler.nodes.type.StampTool.isPointerNonNull; |
265 |
262 |
272 |
269 |
273 import jdk.internal.vm.compiler.collections.EconomicMap; |
270 import jdk.internal.vm.compiler.collections.EconomicMap; |
274 import jdk.internal.vm.compiler.collections.Equivalence; |
271 import jdk.internal.vm.compiler.collections.Equivalence; |
275 import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; |
272 import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap; |
276 import org.graalvm.compiler.api.replacements.Fold; |
273 import org.graalvm.compiler.api.replacements.Fold; |
274 import org.graalvm.compiler.api.replacements.MethodSubstitution; |
|
277 import org.graalvm.compiler.api.replacements.Snippet; |
275 import org.graalvm.compiler.api.replacements.Snippet; |
278 import org.graalvm.compiler.bytecode.Bytecode; |
276 import org.graalvm.compiler.bytecode.Bytecode; |
279 import org.graalvm.compiler.bytecode.BytecodeDisassembler; |
277 import org.graalvm.compiler.bytecode.BytecodeDisassembler; |
280 import org.graalvm.compiler.bytecode.BytecodeLookupSwitch; |
278 import org.graalvm.compiler.bytecode.BytecodeLookupSwitch; |
281 import org.graalvm.compiler.bytecode.BytecodeProvider; |
279 import org.graalvm.compiler.bytecode.BytecodeProvider; |
286 import org.graalvm.compiler.bytecode.Bytes; |
284 import org.graalvm.compiler.bytecode.Bytes; |
287 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; |
285 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; |
288 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider; |
286 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider; |
289 import org.graalvm.compiler.core.common.GraalOptions; |
287 import org.graalvm.compiler.core.common.GraalOptions; |
290 import org.graalvm.compiler.core.common.PermanentBailoutException; |
288 import org.graalvm.compiler.core.common.PermanentBailoutException; |
289 import org.graalvm.compiler.core.common.RetryableBailoutException; |
|
291 import org.graalvm.compiler.core.common.calc.CanonicalCondition; |
290 import org.graalvm.compiler.core.common.calc.CanonicalCondition; |
292 import org.graalvm.compiler.core.common.calc.Condition; |
291 import org.graalvm.compiler.core.common.calc.Condition; |
293 import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition; |
292 import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition; |
294 import org.graalvm.compiler.core.common.calc.FloatConvert; |
293 import org.graalvm.compiler.core.common.calc.FloatConvert; |
295 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; |
294 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; |
353 import org.graalvm.compiler.nodes.StartNode; |
352 import org.graalvm.compiler.nodes.StartNode; |
354 import org.graalvm.compiler.nodes.StateSplit; |
353 import org.graalvm.compiler.nodes.StateSplit; |
355 import org.graalvm.compiler.nodes.StructuredGraph; |
354 import org.graalvm.compiler.nodes.StructuredGraph; |
356 import org.graalvm.compiler.nodes.UnwindNode; |
355 import org.graalvm.compiler.nodes.UnwindNode; |
357 import org.graalvm.compiler.nodes.ValueNode; |
356 import org.graalvm.compiler.nodes.ValueNode; |
357 import org.graalvm.compiler.nodes.ValuePhiNode; |
|
358 import org.graalvm.compiler.nodes.calc.AddNode; |
358 import org.graalvm.compiler.nodes.calc.AddNode; |
359 import org.graalvm.compiler.nodes.calc.AndNode; |
359 import org.graalvm.compiler.nodes.calc.AndNode; |
360 import org.graalvm.compiler.nodes.calc.CompareNode; |
360 import org.graalvm.compiler.nodes.calc.CompareNode; |
361 import org.graalvm.compiler.nodes.calc.ConditionalNode; |
361 import org.graalvm.compiler.nodes.calc.ConditionalNode; |
362 import org.graalvm.compiler.nodes.calc.FloatConvertNode; |
362 import org.graalvm.compiler.nodes.calc.FloatConvertNode; |
363 import org.graalvm.compiler.nodes.calc.FloatDivNode; |
363 import org.graalvm.compiler.nodes.calc.FloatDivNode; |
364 import org.graalvm.compiler.nodes.calc.FloatNormalizeCompareNode; |
|
364 import org.graalvm.compiler.nodes.calc.IntegerBelowNode; |
365 import org.graalvm.compiler.nodes.calc.IntegerBelowNode; |
365 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; |
366 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; |
366 import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; |
367 import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; |
368 import org.graalvm.compiler.nodes.calc.IntegerNormalizeCompareNode; |
|
367 import org.graalvm.compiler.nodes.calc.IsNullNode; |
369 import org.graalvm.compiler.nodes.calc.IsNullNode; |
368 import org.graalvm.compiler.nodes.calc.LeftShiftNode; |
370 import org.graalvm.compiler.nodes.calc.LeftShiftNode; |
369 import org.graalvm.compiler.nodes.calc.MulNode; |
371 import org.graalvm.compiler.nodes.calc.MulNode; |
370 import org.graalvm.compiler.nodes.calc.NarrowNode; |
372 import org.graalvm.compiler.nodes.calc.NarrowNode; |
371 import org.graalvm.compiler.nodes.calc.NegateNode; |
373 import org.graalvm.compiler.nodes.calc.NegateNode; |
372 import org.graalvm.compiler.nodes.calc.NormalizeCompareNode; |
|
373 import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; |
374 import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; |
374 import org.graalvm.compiler.nodes.calc.OrNode; |
375 import org.graalvm.compiler.nodes.calc.OrNode; |
375 import org.graalvm.compiler.nodes.calc.RemNode; |
376 import org.graalvm.compiler.nodes.calc.RemNode; |
376 import org.graalvm.compiler.nodes.calc.RightShiftNode; |
377 import org.graalvm.compiler.nodes.calc.RightShiftNode; |
377 import org.graalvm.compiler.nodes.calc.SignExtendNode; |
378 import org.graalvm.compiler.nodes.calc.SignExtendNode; |
388 import org.graalvm.compiler.nodes.extended.ForeignCallNode; |
389 import org.graalvm.compiler.nodes.extended.ForeignCallNode; |
389 import org.graalvm.compiler.nodes.extended.GuardingNode; |
390 import org.graalvm.compiler.nodes.extended.GuardingNode; |
390 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; |
391 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; |
391 import org.graalvm.compiler.nodes.extended.LoadArrayComponentHubNode; |
392 import org.graalvm.compiler.nodes.extended.LoadArrayComponentHubNode; |
392 import org.graalvm.compiler.nodes.extended.LoadHubNode; |
393 import org.graalvm.compiler.nodes.extended.LoadHubNode; |
393 import org.graalvm.compiler.nodes.extended.LoadMethodNode; |
|
394 import org.graalvm.compiler.nodes.extended.MembarNode; |
394 import org.graalvm.compiler.nodes.extended.MembarNode; |
395 import org.graalvm.compiler.nodes.extended.StateSplitProxyNode; |
395 import org.graalvm.compiler.nodes.extended.StateSplitProxyNode; |
396 import org.graalvm.compiler.nodes.extended.ValueAnchorNode; |
|
397 import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin; |
396 import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin; |
398 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; |
397 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; |
399 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; |
398 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; |
400 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; |
399 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; |
401 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; |
400 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; |
447 import jdk.vm.ci.meta.JavaField; |
446 import jdk.vm.ci.meta.JavaField; |
448 import jdk.vm.ci.meta.JavaKind; |
447 import jdk.vm.ci.meta.JavaKind; |
449 import jdk.vm.ci.meta.JavaMethod; |
448 import jdk.vm.ci.meta.JavaMethod; |
450 import jdk.vm.ci.meta.JavaType; |
449 import jdk.vm.ci.meta.JavaType; |
451 import jdk.vm.ci.meta.JavaTypeProfile; |
450 import jdk.vm.ci.meta.JavaTypeProfile; |
452 import jdk.vm.ci.meta.JavaTypeProfile.ProfiledType; |
|
453 import jdk.vm.ci.meta.LineNumberTable; |
451 import jdk.vm.ci.meta.LineNumberTable; |
454 import jdk.vm.ci.meta.MetaAccessProvider; |
452 import jdk.vm.ci.meta.MetaAccessProvider; |
455 import jdk.vm.ci.meta.ProfilingInfo; |
453 import jdk.vm.ci.meta.ProfilingInfo; |
456 import jdk.vm.ci.meta.RawConstant; |
454 import jdk.vm.ci.meta.RawConstant; |
457 import jdk.vm.ci.meta.ResolvedJavaField; |
455 import jdk.vm.ci.meta.ResolvedJavaField; |
625 throw GraalError.shouldNotReachHere("Unexpected return kind mismatch in " + parser.method + " at FS " + fs); |
623 throw GraalError.shouldNotReachHere("Unexpected return kind mismatch in " + parser.method + " at FS " + fs); |
626 } |
624 } |
627 } |
625 } |
628 |
626 |
629 static class IntrinsicScope extends InliningScope { |
627 static class IntrinsicScope extends InliningScope { |
630 boolean sawInvalidFrameState; |
628 ArrayList<StateSplit> invalidStateUsers; |
631 |
629 |
632 IntrinsicScope(BytecodeParser parser) { |
630 IntrinsicScope(BytecodeParser parser) { |
633 super(parser); |
631 super(parser); |
634 } |
632 } |
635 |
633 |
636 IntrinsicScope(BytecodeParser parser, ResolvedJavaMethod callee, ValueNode[] args) { |
634 IntrinsicScope(BytecodeParser parser, ResolvedJavaMethod callee, ValueNode[] args) { |
637 super(parser, callee, args); |
635 super(parser, callee, args); |
638 } |
636 } |
639 |
637 |
638 @SuppressWarnings("unlikely-arg-type") |
|
640 @Override |
639 @Override |
641 public void close() { |
640 public void close() { |
642 IntrinsicContext intrinsic = parser.intrinsicContext; |
641 IntrinsicContext intrinsic = parser.intrinsicContext; |
643 boolean isRootCompilation; |
642 boolean isRootCompilation; |
644 if (intrinsic != null) { |
643 if (intrinsic != null) { |
648 isRootCompilation = intrinsic.isCompilationRoot(); |
647 isRootCompilation = intrinsic.isCompilationRoot(); |
649 } else { |
648 } else { |
650 isRootCompilation = false; |
649 isRootCompilation = false; |
651 } |
650 } |
652 processPlaceholderFrameStates(isRootCompilation); |
651 processPlaceholderFrameStates(isRootCompilation); |
653 if (sawInvalidFrameState) { |
652 if (invalidStateUsers != null) { |
654 JavaKind returnKind = parser.getInvokeReturnType().getJavaKind(); |
653 JavaKind returnKind = parser.getInvokeReturnType().getJavaKind(); |
655 FrameStateBuilder frameStateBuilder = parser.frameState; |
654 ValueNode returnValue = parser.frameState.pop(returnKind); |
656 ValueNode returnValue = frameStateBuilder.pop(returnKind); |
655 if (invalidStateUsers.size() == 1 && invalidStateUsers.get(0) == parser.lastInstr) { |
657 StructuredGraph graph = parser.lastInstr.graph(); |
656 updateSplitFrameState(invalidStateUsers.get(0), returnKind, returnValue); |
658 StateSplitProxyNode proxy = graph.add(new StateSplitProxyNode(returnValue)); |
657 } else if (parser.lastInstr instanceof MergeNode) { |
659 parser.lastInstr.setNext(proxy); |
658 ValuePhiNode returnValues = null; |
660 frameStateBuilder.push(returnKind, proxy); |
659 MergeNode merge = (MergeNode) parser.lastInstr; |
661 proxy.setStateAfter(parser.createFrameState(parser.stream.nextBCI(), proxy)); |
660 |
662 parser.lastInstr = proxy; |
661 if (returnValue instanceof ValuePhiNode && ((ValuePhiNode) returnValue).merge() == parser.lastInstr) { |
662 returnValues = (ValuePhiNode) returnValue; |
|
663 } |
|
664 if (invalidStateUsers.remove(merge)) { |
|
665 updateSplitFrameState(merge, returnKind, returnValue); |
|
666 } |
|
667 for (EndNode pred : merge.cfgPredecessors()) { |
|
668 Node lastPred = pred.predecessor(); |
|
669 if (invalidStateUsers.remove(lastPred)) { |
|
670 ValueNode predReturnValue = returnValue; |
|
671 if (returnValues != null) { |
|
672 int index = merge.phiPredecessorIndex(pred); |
|
673 predReturnValue = ((ValuePhiNode) returnValue).valueAt(index); |
|
674 } |
|
675 updateSplitFrameState((StateSplit) lastPred, returnKind, predReturnValue); |
|
676 } |
|
677 } |
|
678 if (invalidStateUsers.size() != 0) { |
|
679 throw new GraalError("unexpected StateSplit above merge %s", invalidStateUsers); |
|
680 } |
|
681 } else { |
|
682 throw new GraalError("unexpected node between return StateSplit and last instruction %s", parser.lastInstr); |
|
683 } |
|
684 // Restore the original return value |
|
685 parser.frameState.push(returnKind, returnValue); |
|
686 } |
|
687 } |
|
688 |
|
689 private void updateSplitFrameState(StateSplit split, JavaKind returnKind, ValueNode returnValue) { |
|
690 parser.frameState.push(returnKind, returnValue); |
|
691 FrameState oldState = split.stateAfter(); |
|
692 split.setStateAfter(parser.createFrameState(parser.stream.nextBCI(), split)); |
|
693 parser.frameState.pop(returnKind); |
|
694 if (oldState.hasNoUsages()) { |
|
695 oldState.safeDelete(); |
|
663 } |
696 } |
664 } |
697 } |
665 |
698 |
666 @Override |
699 @Override |
667 protected void handleReturnMismatch(StructuredGraph g, FrameState fs) { |
700 protected void handleReturnMismatch(StructuredGraph g, FrameState fs) { |
668 // If the intrinsic returns a non-void value, then any frame |
701 if (invalidStateUsers == null) { |
669 // state with an empty stack is invalid as it cannot |
702 invalidStateUsers = new ArrayList<>(); |
670 // be used to deoptimize to just after the call returns. |
703 } |
671 // These invalid frame states are expected to be removed |
704 for (Node use : fs.usages()) { |
672 // by later compilation stages. |
705 if (!(use instanceof StateSplit)) { |
673 FrameState newFrameState = g.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI)); |
706 throw new GraalError("Expected StateSplit for return mismatch"); |
674 newFrameState.setNodeSourcePosition(fs.getNodeSourcePosition()); |
707 } |
675 fs.replaceAndDelete(newFrameState); |
708 invalidStateUsers.add((StateSplit) use); |
676 sawInvalidFrameState = true; |
709 } |
677 } |
710 } |
678 } |
711 } |
679 |
712 |
680 private static class Target { |
713 private static class Target { |
681 final FixedNode entry; |
714 final FixedNode entry; |
777 this.intrinsicContext = intrinsicContext; |
810 this.intrinsicContext = intrinsicContext; |
778 this.entryBCI = entryBCI; |
811 this.entryBCI = entryBCI; |
779 this.parent = parent; |
812 this.parent = parent; |
780 |
813 |
781 ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin(); |
814 ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin(); |
782 if (classInitializationPlugin != null && graphBuilderConfig.eagerResolving()) { |
815 if (classInitializationPlugin != null && graphBuilderConfig.eagerResolving() && classInitializationPlugin.supportsLazyInitialization(constantPool)) { |
783 uninitializedIsError = eagerInitializing = !classInitializationPlugin.supportsLazyInitialization(constantPool); |
816 eagerInitializing = false; |
817 uninitializedIsError = false; |
|
784 } else { |
818 } else { |
785 eagerInitializing = graphBuilderConfig.eagerResolving(); |
819 eagerInitializing = graphBuilderConfig.eagerResolving(); |
786 uninitializedIsError = graphBuilderConfig.unresolvedIsError(); |
820 uninitializedIsError = graphBuilderConfig.unresolvedIsError(); |
787 } |
821 } |
788 |
822 |
997 } else if (!beginNode.hasUsages()) { |
1031 } else if (!beginNode.hasUsages()) { |
998 GraphUtil.unlinkFixedNode(beginNode); |
1032 GraphUtil.unlinkFixedNode(beginNode); |
999 beginNode.safeDelete(); |
1033 beginNode.safeDelete(); |
1000 } |
1034 } |
1001 } |
1035 } |
1036 if (graph.isOSR() && getParent() == null && graph.getNodes().filter(EntryMarkerNode.class).isEmpty()) { |
|
1037 // This should generally be a transient condition because of inconsistent profile |
|
1038 // information. |
|
1039 throw new RetryableBailoutException("OSR entry point wasn't parsed"); |
|
1040 } |
|
1002 } |
1041 } |
1003 |
1042 |
1004 /** |
1043 /** |
1005 * Creates the frame state after the start node of a graph for an {@link IntrinsicContext |
1044 * Creates the frame state after the start node of a graph for an {@link IntrinsicContext |
1006 * intrinsic} that is the parse root (either for root compiling or for post-parse inlining). |
1045 * intrinsic} that is the parse root (either for root compiling or for post-parse inlining). |
1293 protected ValueNode genXor(ValueNode x, ValueNode y) { |
1332 protected ValueNode genXor(ValueNode x, ValueNode y) { |
1294 return XorNode.create(x, y, NodeView.DEFAULT); |
1333 return XorNode.create(x, y, NodeView.DEFAULT); |
1295 } |
1334 } |
1296 |
1335 |
1297 protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) { |
1336 protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) { |
1298 return NormalizeCompareNode.create(x, y, isUnorderedLess, JavaKind.Int, getConstantReflection()); |
1337 return FloatNormalizeCompareNode.create(x, y, isUnorderedLess, JavaKind.Int, getConstantReflection()); |
1338 } |
|
1339 |
|
1340 protected ValueNode genIntegerNormalizeCompare(ValueNode x, ValueNode y) { |
|
1341 return IntegerNormalizeCompareNode.create(x, y, false, JavaKind.Int, getConstantReflection()); |
|
1299 } |
1342 } |
1300 |
1343 |
1301 protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) { |
1344 protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) { |
1302 return FloatConvertNode.create(op, input, NodeView.DEFAULT); |
1345 return FloatConvertNode.create(op, input, NodeView.DEFAULT); |
1303 } |
1346 } |
1366 |
1409 |
1367 protected AnchoringNode createAnchor(JavaTypeProfile profile) { |
1410 protected AnchoringNode createAnchor(JavaTypeProfile profile) { |
1368 if (profile == null || profile.getNotRecordedProbability() > 0.0) { |
1411 if (profile == null || profile.getNotRecordedProbability() > 0.0) { |
1369 return null; |
1412 return null; |
1370 } else { |
1413 } else { |
1371 return append(new ValueAnchorNode(null)); |
1414 return BeginNode.prevBegin(lastInstr); |
1372 } |
1415 } |
1373 } |
1416 } |
1374 |
1417 |
1375 protected LogicNode createInstanceOf(TypeReference type, ValueNode object, JavaTypeProfile profile) { |
1418 protected LogicNode createInstanceOf(TypeReference type, ValueNode object, JavaTypeProfile profile) { |
1376 return InstanceOfNode.create(type, object, profile, createAnchor(profile)); |
1419 return InstanceOfNode.create(type, object, profile, createAnchor(profile)); |
1732 append(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint)); |
1775 append(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint)); |
1733 frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, graph)); |
1776 frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, graph)); |
1734 return null; |
1777 return null; |
1735 } |
1778 } |
1736 |
1779 |
1737 JavaType returnType = targetMethod.getSignature().getReturnType(method.getDeclaringClass()); |
1780 JavaType returnType = maybeEagerlyResolve(targetMethod.getSignature().getReturnType(method.getDeclaringClass()), targetMethod.getDeclaringClass()); |
1738 if (graphBuilderConfig.eagerResolving() || parsingIntrinsic()) { |
|
1739 returnType = returnType.resolve(targetMethod.getDeclaringClass()); |
|
1740 } |
|
1741 if (invokeKind.hasReceiver()) { |
1781 if (invokeKind.hasReceiver()) { |
1742 args[0] = maybeEmitExplicitNullCheck(args[0]); |
1782 args[0] = maybeEmitExplicitNullCheck(args[0]); |
1743 } |
1783 } |
1744 |
1784 |
1745 if (initialInvokeKind == InvokeKind.Special && !targetMethod.isConstructor()) { |
1785 if (initialInvokeKind == InvokeKind.Special && !targetMethod.isConstructor()) { |
1761 if (invokeKind.hasReceiver() && args[0].isNullConstant()) { |
1801 if (invokeKind.hasReceiver() && args[0].isNullConstant()) { |
1762 append(new DeoptimizeNode(InvalidateRecompile, NullCheckException)); |
1802 append(new DeoptimizeNode(InvalidateRecompile, NullCheckException)); |
1763 return null; |
1803 return null; |
1764 } |
1804 } |
1765 |
1805 |
1766 if (!invokeKind.isIndirect() || (UseGuardedIntrinsics.getValue(options) && !GeneratePIC.getValue(options))) { |
1806 if (!invokeKind.isIndirect()) { |
1767 if (tryInvocationPlugin(invokeKind, args, targetMethod, resultType, returnType)) { |
1807 if (tryInvocationPlugin(invokeKind, args, targetMethod, resultType)) { |
1768 if (TraceParserPlugins.getValue(options)) { |
1808 if (TraceParserPlugins.getValue(options)) { |
1769 traceWithContext("used invocation plugin for %s", targetMethod.format("%h.%n(%p)")); |
1809 traceWithContext("used invocation plugin for %s", targetMethod.format("%h.%n(%p)")); |
1770 } |
1810 } |
1771 return null; |
1811 return null; |
1772 } |
1812 } |
2038 } |
2078 } |
2039 return true; |
2079 return true; |
2040 } |
2080 } |
2041 } |
2081 } |
2042 |
2082 |
2043 protected static class IntrinsicGuard { |
|
2044 final FixedWithNextNode lastInstr; |
|
2045 final Mark mark; |
|
2046 final AbstractBeginNode nonIntrinsicBranch; |
|
2047 final ValueNode receiver; |
|
2048 final JavaTypeProfile profile; |
|
2049 |
|
2050 public IntrinsicGuard(FixedWithNextNode lastInstr, ValueNode receiver, Mark mark, AbstractBeginNode nonIntrinsicBranch, JavaTypeProfile profile) { |
|
2051 this.lastInstr = lastInstr; |
|
2052 this.receiver = receiver; |
|
2053 this.mark = mark; |
|
2054 this.nonIntrinsicBranch = nonIntrinsicBranch; |
|
2055 this.profile = profile; |
|
2056 } |
|
2057 } |
|
2058 |
|
2059 /** |
|
2060 * Weaves a test of the receiver type to ensure the dispatch will select {@code targetMethod} |
|
2061 * and not another method that overrides it. This should only be called if there is an |
|
2062 * {@link InvocationPlugin} for {@code targetMethod} and the invocation is indirect. |
|
2063 * |
|
2064 * The control flow woven around the intrinsic is as follows: |
|
2065 * |
|
2066 * <pre> |
|
2067 * if (LoadMethod(LoadHub(receiver)) == targetMethod) { |
|
2068 * <intrinsic for targetMethod> |
|
2069 * } else { |
|
2070 * <virtual call to targetMethod> |
|
2071 * } |
|
2072 * </pre> |
|
2073 * |
|
2074 * The {@code else} branch is woven by {@link #afterInvocationPluginExecution}. |
|
2075 * |
|
2076 * @return {@code null} if the intrinsic cannot be used otherwise an object to be used by |
|
2077 * {@link #afterInvocationPluginExecution} to weave code for the non-intrinsic branch |
|
2078 */ |
|
2079 protected IntrinsicGuard guardIntrinsic(ValueNode[] args, ResolvedJavaMethod targetMethod, InvocationPluginReceiver pluginReceiver) { |
|
2080 ValueNode intrinsicReceiver = args[0]; |
|
2081 ResolvedJavaType receiverType = StampTool.typeOrNull(intrinsicReceiver); |
|
2082 if (receiverType == null) { |
|
2083 // The verifier guarantees it to be at least type declaring targetMethod |
|
2084 receiverType = targetMethod.getDeclaringClass(); |
|
2085 } |
|
2086 ResolvedJavaMethod resolvedMethod = receiverType.resolveMethod(targetMethod, method.getDeclaringClass()); |
|
2087 if (resolvedMethod == null || resolvedMethod.equals(targetMethod)) { |
|
2088 assert resolvedMethod == null || targetMethod.getDeclaringClass().isAssignableFrom(resolvedMethod.getDeclaringClass()); |
|
2089 Mark mark = graph.getMark(); |
|
2090 FixedWithNextNode currentLastInstr = lastInstr; |
|
2091 ValueNode nonNullReceiver = pluginReceiver.get(); |
|
2092 Stamp methodStamp = getStampProvider().createMethodStamp(); |
|
2093 LoadHubNode hub = graph.unique(new LoadHubNode(getStampProvider(), nonNullReceiver)); |
|
2094 LoadMethodNode actual = append(new LoadMethodNode(methodStamp, targetMethod, receiverType, method.getDeclaringClass(), hub)); |
|
2095 ConstantNode expected = graph.unique(ConstantNode.forConstant(methodStamp, targetMethod.getEncoding(), getMetaAccess())); |
|
2096 LogicNode compare = graph.addOrUniqueWithInputs( |
|
2097 CompareNode.createCompareNode(getConstantReflection(), getMetaAccess(), options, null, CanonicalCondition.EQ, actual, expected, NodeView.DEFAULT)); |
|
2098 |
|
2099 JavaTypeProfile profile = null; |
|
2100 if (profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) { |
|
2101 profile = profilingInfo.getTypeProfile(bci()); |
|
2102 if (profile != null) { |
|
2103 JavaTypeProfile newProfile = adjustProfileForInvocationPlugin(profile, targetMethod); |
|
2104 if (newProfile != profile) { |
|
2105 if (newProfile.getTypes().length == 0) { |
|
2106 // All profiled types select the intrinsic so |
|
2107 // emit a fixed guard instead of an if-then-else. |
|
2108 lastInstr = append(new FixedGuardNode(compare, TypeCheckedInliningViolated, InvalidateReprofile, false)); |
|
2109 return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, null, null); |
|
2110 } |
|
2111 } else { |
|
2112 // No profiled types select the intrinsic so emit a virtual call |
|
2113 return null; |
|
2114 } |
|
2115 profile = newProfile; |
|
2116 } |
|
2117 } |
|
2118 |
|
2119 AbstractBeginNode intrinsicBranch = graph.add(new BeginNode()); |
|
2120 AbstractBeginNode nonIntrinsicBranch = graph.add(new BeginNode()); |
|
2121 // In the adjustment above, we filter out receiver types that select the intrinsic as |
|
2122 // virtual call target. This means the recorded types in the adjusted profile will |
|
2123 // definitely not call into the intrinsic. Note that the following branch probability is |
|
2124 // still not precise -- the previously-not-recorded receiver types in the original |
|
2125 // profile might or might not call into the intrinsic. Yet we accumulate them into the |
|
2126 // probability of the intrinsic branch, assuming that the not-recorded types will only |
|
2127 // be a small fraction. |
|
2128 append(new IfNode(compare, intrinsicBranch, nonIntrinsicBranch, profile != null ? profile.getNotRecordedProbability() : LIKELY_PROBABILITY)); |
|
2129 lastInstr = intrinsicBranch; |
|
2130 return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, nonIntrinsicBranch, profile); |
|
2131 } else { |
|
2132 // Receiver selects an overriding method so emit a virtual call |
|
2133 return null; |
|
2134 } |
|
2135 } |
|
2136 |
|
2137 /** |
|
2138 * Adjusts the profile for an indirect invocation of a virtual method for which there is an |
|
2139 * intrinsic. The adjustment made by this method is to remove all types from the profile that do |
|
2140 * not override {@code targetMethod}. |
|
2141 * |
|
2142 * @param profile the profile to adjust |
|
2143 * @param targetMethod the virtual method for which there is an intrinsic |
|
2144 * @return the adjusted profile or the original {@code profile} object if no adjustment was made |
|
2145 */ |
|
2146 protected JavaTypeProfile adjustProfileForInvocationPlugin(JavaTypeProfile profile, ResolvedJavaMethod targetMethod) { |
|
2147 if (profile.getTypes().length > 0) { |
|
2148 List<ProfiledType> retained = new ArrayList<>(); |
|
2149 double notRecordedProbability = profile.getNotRecordedProbability(); |
|
2150 for (ProfiledType ptype : profile.getTypes()) { |
|
2151 if (!ptype.getType().resolveMethod(targetMethod, method.getDeclaringClass()).equals(targetMethod)) { |
|
2152 retained.add(ptype); |
|
2153 } else { |
|
2154 notRecordedProbability += ptype.getProbability(); |
|
2155 } |
|
2156 } |
|
2157 if (!retained.isEmpty()) { |
|
2158 if (retained.size() != profile.getTypes().length) { |
|
2159 return new JavaTypeProfile(profile.getNullSeen(), notRecordedProbability, retained.toArray(new ProfiledType[retained.size()])); |
|
2160 } |
|
2161 } else { |
|
2162 return new JavaTypeProfile(profile.getNullSeen(), notRecordedProbability, new ProfiledType[0]); |
|
2163 } |
|
2164 } |
|
2165 return profile; |
|
2166 } |
|
2167 |
|
2168 /** |
|
2169 * Performs any action required after execution of an invocation plugin. This includes |
|
2170 * {@linkplain InvocationPluginAssertions#check checking} invocation plugin invariants as well |
|
2171 * as weaving the {@code else} branch of the code woven by {@link #guardIntrinsic} if |
|
2172 * {@code guard != null}. |
|
2173 */ |
|
2174 protected void afterInvocationPluginExecution(boolean pluginHandledInvoke, InvocationPluginAssertions assertions, IntrinsicGuard intrinsicGuard, |
|
2175 InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) { |
|
2176 assert assertions.check(pluginHandledInvoke); |
|
2177 if (intrinsicGuard != null) { |
|
2178 if (pluginHandledInvoke) { |
|
2179 if (intrinsicGuard.nonIntrinsicBranch != null) { |
|
2180 // Intrinsic emitted: emit a virtual call to the target method and |
|
2181 // merge it with the intrinsic branch |
|
2182 EndNode intrinsicEnd = append(new EndNode()); |
|
2183 |
|
2184 FrameStateBuilder intrinsicState = null; |
|
2185 FrameStateBuilder nonIntrinisicState = null; |
|
2186 if (resultType != JavaKind.Void) { |
|
2187 intrinsicState = frameState.copy(); |
|
2188 frameState.pop(resultType); |
|
2189 nonIntrinisicState = frameState; |
|
2190 } |
|
2191 |
|
2192 lastInstr = intrinsicGuard.nonIntrinsicBranch; |
|
2193 createNonInlinedInvoke(getActionForInvokeExceptionEdge(null), bci(), args, targetMethod, invokeKind, resultType, returnType, intrinsicGuard.profile); |
|
2194 |
|
2195 EndNode nonIntrinsicEnd = append(new EndNode()); |
|
2196 AbstractMergeNode mergeNode = graph.add(new MergeNode()); |
|
2197 |
|
2198 mergeNode.addForwardEnd(intrinsicEnd); |
|
2199 if (intrinsicState != null) { |
|
2200 intrinsicState.merge(mergeNode, nonIntrinisicState); |
|
2201 frameState = intrinsicState; |
|
2202 } |
|
2203 mergeNode.addForwardEnd(nonIntrinsicEnd); |
|
2204 mergeNode.setStateAfter(frameState.create(stream.nextBCI(), mergeNode)); |
|
2205 |
|
2206 lastInstr = mergeNode; |
|
2207 } |
|
2208 } else { |
|
2209 // Intrinsic was not applied: remove intrinsic guard |
|
2210 // and restore the original receiver node in the arguments array |
|
2211 intrinsicGuard.lastInstr.setNext(null); |
|
2212 GraphUtil.removeNewNodes(graph, intrinsicGuard.mark); |
|
2213 lastInstr = intrinsicGuard.lastInstr; |
|
2214 args[0] = intrinsicGuard.receiver; |
|
2215 } |
|
2216 } |
|
2217 } |
|
2218 |
|
2219 @SuppressWarnings("try") |
2083 @SuppressWarnings("try") |
2220 protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) { |
2084 protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) { |
2221 InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod); |
2085 InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod); |
2222 if (plugin != null) { |
2086 if (plugin != null) { |
2223 |
2087 |
2224 if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) { |
2088 if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) { |
2225 // Self recursive intrinsic means the original method should be called. |
2089 // Self recursive intrinsic means the original method should be called. |
2226 return false; |
2090 return false; |
2227 } |
2091 } |
2228 |
2092 |
2229 InvocationPluginReceiver pluginReceiver = invocationPluginReceiver.init(targetMethod, args); |
2093 InvocationPluginReceiver pluginReceiver = invocationPluginReceiver.init(targetMethod, args); |
2230 |
2094 assert invokeKind.isDirect() : "Cannot apply invocation plugin on an indirect call site."; |
2231 IntrinsicGuard intrinsicGuard = null; |
|
2232 if (invokeKind.isIndirect()) { |
|
2233 intrinsicGuard = guardIntrinsic(args, targetMethod, pluginReceiver); |
|
2234 if (intrinsicGuard == null) { |
|
2235 return false; |
|
2236 } else if (intrinsicGuard.nonIntrinsicBranch == null) { |
|
2237 assert lastInstr instanceof FixedGuardNode; |
|
2238 } |
|
2239 } |
|
2240 |
2095 |
2241 InvocationPluginAssertions assertions = Assertions.assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null; |
2096 InvocationPluginAssertions assertions = Assertions.assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null; |
2242 try (DebugCloseable context = openNodeContext(targetMethod)) { |
2097 try (DebugCloseable context = openNodeContext(targetMethod)) { |
2243 if (plugin.execute(this, targetMethod, pluginReceiver, args)) { |
2098 if (plugin.execute(this, targetMethod, pluginReceiver, args)) { |
2244 afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType); |
2099 assert assertions.check(true); |
2245 return !plugin.isDecorator(); |
2100 return !plugin.isDecorator(); |
2246 } else { |
2101 } else { |
2247 afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType); |
2102 assert assertions.check(false); |
2248 } |
2103 } |
2249 } |
2104 } |
2250 } |
2105 } |
2251 return false; |
2106 return false; |
2252 } |
2107 } |
2628 |
2483 |
2629 protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) { |
2484 protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) { |
2630 FixedWithNextNode calleeBeforeUnwindNode = null; |
2485 FixedWithNextNode calleeBeforeUnwindNode = null; |
2631 ValueNode calleeUnwindValue = null; |
2486 ValueNode calleeUnwindValue = null; |
2632 |
2487 |
2633 try (InliningScope s = parsingIntrinsic() ? null : (calleeIntrinsicContext != null ? new IntrinsicScope(this, targetMethod, args) |
2488 try (InliningScope s = parsingIntrinsic() ? null |
2634 : new InliningScope(this, targetMethod, args))) { |
2489 : (calleeIntrinsicContext != null ? new IntrinsicScope(this, targetMethod, args) |
2490 : new InliningScope(this, targetMethod, args))) { |
|
2635 BytecodeParser parser = graphBuilderInstance.createBytecodeParser(graph, this, targetMethod, INVOCATION_ENTRY_BCI, calleeIntrinsicContext); |
2491 BytecodeParser parser = graphBuilderInstance.createBytecodeParser(graph, this, targetMethod, INVOCATION_ENTRY_BCI, calleeIntrinsicContext); |
2636 FrameStateBuilder startFrameState = new FrameStateBuilder(parser, parser.code, graph, graphBuilderConfig.retainLocalVariables()); |
2492 boolean targetIsSubstitution = targetMethod.isAnnotationPresent(MethodSubstitution.class); |
2493 FrameStateBuilder startFrameState = new FrameStateBuilder(parser, parser.code, graph, graphBuilderConfig.retainLocalVariables() && !targetIsSubstitution); |
|
2637 if (!targetMethod.isStatic()) { |
2494 if (!targetMethod.isStatic()) { |
2638 args[0] = nullCheckedValue(args[0]); |
2495 args[0] = nullCheckedValue(args[0]); |
2639 } |
2496 } |
2640 startFrameState.initializeFromArgumentsArray(args); |
2497 startFrameState.initializeFromArgumentsArray(args); |
2641 parser.build(this.lastInstr, startFrameState); |
2498 parser.build(this.lastInstr, startFrameState); |
2642 |
2499 |
2643 List<ReturnToCallerData> calleeReturnDataList = parser.returnDataList; |
2500 List<ReturnToCallerData> calleeReturnDataList = parser.returnDataList; |
2644 |
2501 |
2645 processCalleeReturn(targetMethod, s, calleeReturnDataList); |
|
2646 /* |
2502 /* |
2647 * Propagate any side effects into the caller when parsing intrinsics. |
2503 * Propagate any side effects into the caller when parsing intrinsics. |
2648 */ |
2504 */ |
2649 if (parser.frameState.isAfterSideEffect() && parsingIntrinsic()) { |
2505 if (parser.frameState.isAfterSideEffect() && parsingIntrinsic()) { |
2650 for (StateSplit sideEffect : parser.frameState.sideEffects()) { |
2506 for (StateSplit sideEffect : parser.frameState.sideEffects()) { |
2651 frameState.addSideEffect(sideEffect); |
2507 frameState.addSideEffect(sideEffect); |
2652 } |
2508 } |
2653 } |
2509 } |
2510 |
|
2511 processCalleeReturn(targetMethod, s, calleeReturnDataList); |
|
2654 |
2512 |
2655 calleeBeforeUnwindNode = parser.getBeforeUnwindNode(); |
2513 calleeBeforeUnwindNode = parser.getBeforeUnwindNode(); |
2656 if (calleeBeforeUnwindNode != null) { |
2514 if (calleeBeforeUnwindNode != null) { |
2657 calleeUnwindValue = parser.getUnwindValue(); |
2515 calleeUnwindValue = parser.getUnwindValue(); |
2658 assert calleeUnwindValue != null; |
2516 assert calleeUnwindValue != null; |
2741 StateSplit stateSplit = (StateSplit) returnVal; |
2599 StateSplit stateSplit = (StateSplit) returnVal; |
2742 FrameState stateAfter = stateSplit.stateAfter(); |
2600 FrameState stateAfter = stateSplit.stateAfter(); |
2743 if (stateSplit.hasSideEffect()) { |
2601 if (stateSplit.hasSideEffect()) { |
2744 assert stateSplit != null; |
2602 assert stateSplit != null; |
2745 if (stateAfter.bci == BytecodeFrame.AFTER_BCI) { |
2603 if (stateAfter.bci == BytecodeFrame.AFTER_BCI) { |
2746 assert stateAfter.usages().count() == 1; |
2604 assert stateAfter.hasExactlyOneUsage(); |
2747 assert stateAfter.usages().first() == stateSplit; |
2605 assert stateAfter.usages().first() == stateSplit; |
2748 FrameState state; |
2606 FrameState state; |
2749 if (returnVal.getStackKind() == JavaKind.Illegal) { |
2607 if (returnVal.getStackKind() == JavaKind.Illegal) { |
2750 // This should only occur when Fold and NodeIntrinsic plugins are |
2608 // This should only occur when Fold and NodeIntrinsic plugins are |
2751 // deferred. Their return value might not be a Java type and in that |
2609 // deferred. Their return value might not be a Java type and in that |
2846 if (frameState.lockDepth(false) == 0) { |
2704 if (frameState.lockDepth(false) == 0) { |
2847 throw bailout("unbalanced monitors: too many exits"); |
2705 throw bailout("unbalanced monitors: too many exits"); |
2848 } |
2706 } |
2849 MonitorIdNode monitorId = frameState.peekMonitorId(); |
2707 MonitorIdNode monitorId = frameState.peekMonitorId(); |
2850 ValueNode lockedObject = frameState.popLock(); |
2708 ValueNode lockedObject = frameState.popLock(); |
2851 if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) { |
2709 ValueNode originalLockedObject = GraphUtil.originalValue(lockedObject, false); |
2852 throw bailout(String.format("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject))); |
2710 ValueNode originalX = GraphUtil.originalValue(x, false); |
2711 if (originalLockedObject != originalX) { |
|
2712 throw bailout(String.format("unbalanced monitors: mismatch at monitorexit, %s != %s", originalLockedObject, originalX)); |
|
2853 } |
2713 } |
2854 MonitorExitNode monitorExit = append(new MonitorExitNode(lockedObject, monitorId, escapedValue)); |
2714 MonitorExitNode monitorExit = append(new MonitorExitNode(lockedObject, monitorId, escapedValue)); |
2855 monitorExit.setStateAfter(createFrameState(bci, monitorExit)); |
2715 monitorExit.setStateAfter(createFrameState(bci, monitorExit)); |
2856 } |
2716 } |
2857 |
2717 |
3093 /* |
2953 /* |
3094 * This is the first time we see this block as a branch target. Create and return a |
2954 * This is the first time we see this block as a branch target. Create and return a |
3095 * placeholder that later can be replaced with a MergeNode when we see this block |
2955 * placeholder that later can be replaced with a MergeNode when we see this block |
3096 * again. |
2956 * again. |
3097 */ |
2957 */ |
3098 if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader() && (currentBlock.loops & ~block.loops) == 0) { |
2958 if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader() && (currentBlock.loops & ~block.loops) == 0 && |
2959 currentBlock.getJsrScope() == block.getJsrScope()) { |
|
2960 /* |
|
2961 * If we know that no BeginNode is necessary, then we can avoid allocating and |
|
2962 * later removing that node. This is strictly a performance optimization: |
|
2963 * unnecessary BeginNode are allowed and will be removed later on. We need to be |
|
2964 * careful though because the predecessor information is not always enough: when |
|
2965 * the loop level changes, we always need a BeginNode. Also, JSR scope changes |
|
2966 * required a BeginNode because the predecessors coming from RET bytecodes are |
|
2967 * not reflected in the predecessor count. |
|
2968 */ |
|
3099 setFirstInstruction(block, lastInstr); |
2969 setFirstInstruction(block, lastInstr); |
3100 lastInstr = null; |
2970 lastInstr = null; |
3101 } else { |
2971 } else { |
3102 setFirstInstruction(block, graph.add(new BeginNode())); |
2972 setFirstInstruction(block, graph.add(new BeginNode())); |
3103 } |
2973 } |
4153 throw shouldNotReachHere(); |
4023 throw shouldNotReachHere(); |
4154 } |
4024 } |
4155 frameState.push(kind, append(v)); |
4025 frameState.push(kind, append(v)); |
4156 } |
4026 } |
4157 |
4027 |
4158 private void genCompareOp(JavaKind kind, boolean isUnorderedLess) { |
4028 private void genFloatCompareOp(JavaKind kind, boolean isUnorderedLess) { |
4159 ValueNode y = frameState.pop(kind); |
4029 ValueNode y = frameState.pop(kind); |
4160 ValueNode x = frameState.pop(kind); |
4030 ValueNode x = frameState.pop(kind); |
4161 frameState.push(JavaKind.Int, append(genNormalizeCompare(x, y, isUnorderedLess))); |
4031 frameState.push(JavaKind.Int, append(genNormalizeCompare(x, y, isUnorderedLess))); |
4032 } |
|
4033 |
|
4034 private void genIntegerCompareOp(JavaKind kind) { |
|
4035 ValueNode y = frameState.pop(kind); |
|
4036 ValueNode x = frameState.pop(kind); |
|
4037 frameState.push(JavaKind.Int, append(genIntegerNormalizeCompare(x, y))); |
|
4162 } |
4038 } |
4163 |
4039 |
4164 private void genFloatConvert(FloatConvert op, JavaKind from, JavaKind to) { |
4040 private void genFloatConvert(FloatConvert op, JavaKind from, JavaKind to) { |
4165 ValueNode input = frameState.pop(from); |
4041 ValueNode input = frameState.pop(from); |
4166 frameState.push(to, append(genFloatConvert(op, input))); |
4042 frameState.push(to, append(genFloatConvert(op, input))); |
4231 return result; |
4107 return result; |
4232 } |
4108 } |
4233 |
4109 |
4234 private String unresolvedMethodAssertionMessage(JavaMethod result) { |
4110 private String unresolvedMethodAssertionMessage(JavaMethod result) { |
4235 String message = result.format("%H.%n(%P)%R"); |
4111 String message = result.format("%H.%n(%P)%R"); |
4236 if (JavaVersionUtil.Java8OrEarlier) { |
4112 if (JavaVersionUtil.JAVA_SPEC <= 8) { |
4237 JavaType declaringClass = result.getDeclaringClass(); |
4113 JavaType declaringClass = result.getDeclaringClass(); |
4238 String className = declaringClass.getName(); |
4114 String className = declaringClass.getName(); |
4239 switch (className) { |
4115 switch (className) { |
4240 case "Ljava/nio/ByteBuffer;": |
4116 case "Ljava/nio/ByteBuffer;": |
4241 case "Ljava/nio/ShortBuffer;": |
4117 case "Ljava/nio/ShortBuffer;": |
4322 } |
4198 } |
4323 } |
4199 } |
4324 } |
4200 } |
4325 } |
4201 } |
4326 |
4202 |
4203 protected JavaType maybeEagerlyResolve(JavaType type, ResolvedJavaType accessingClass) { |
|
4204 if (graphBuilderConfig.eagerResolving() || parsingIntrinsic()) { |
|
4205 return type.resolve(accessingClass); |
|
4206 } |
|
4207 return type; |
|
4208 } |
|
4209 |
|
4327 protected void maybeEagerlyInitialize(ResolvedJavaType resolvedType) { |
4210 protected void maybeEagerlyInitialize(ResolvedJavaType resolvedType) { |
4328 if (!resolvedType.isInitialized() && eagerInitializing) { |
4211 if (!resolvedType.isInitialized() && eagerInitializing) { |
4329 initialize(resolvedType); |
4212 initialize(resolvedType); |
4330 } |
4213 } |
4331 } |
4214 } |
4934 this.blockIndex = blockSuccessorIndex; |
4817 this.blockIndex = blockSuccessorIndex; |
4935 actualIndex = -1; |
4818 actualIndex = -1; |
4936 } |
4819 } |
4937 } |
4820 } |
4938 |
4821 |
4822 private static final int SWITCH_DEOPT_UNSEEN = -2; |
|
4823 private static final int SWITCH_DEOPT_SEEN = -1; |
|
4824 |
|
4939 private void genSwitch(BytecodeSwitch bs) { |
4825 private void genSwitch(BytecodeSwitch bs) { |
4940 int bci = bci(); |
4826 int bci = bci(); |
4941 ValueNode value = frameState.pop(JavaKind.Int); |
4827 ValueNode value = frameState.pop(JavaKind.Int); |
4942 |
4828 |
4943 int nofCases = bs.numberOfCases(); |
4829 int nofCases = bs.numberOfCases(); |
4951 } |
4837 } |
4952 |
4838 |
4953 ArrayList<BciBlock> actualSuccessors = new ArrayList<>(); |
4839 ArrayList<BciBlock> actualSuccessors = new ArrayList<>(); |
4954 int[] keys = new int[nofCases]; |
4840 int[] keys = new int[nofCases]; |
4955 int[] keySuccessors = new int[nofCasesPlusDefault]; |
4841 int[] keySuccessors = new int[nofCasesPlusDefault]; |
4956 int deoptSuccessorIndex = -1; |
4842 int deoptSuccessorIndex = SWITCH_DEOPT_UNSEEN; |
4957 int nextSuccessorIndex = 0; |
4843 int nextSuccessorIndex = 0; |
4958 boolean constantValue = value.isConstant(); |
4844 boolean constantValue = value.isConstant(); |
4959 for (int i = 0; i < nofCasesPlusDefault; i++) { |
4845 for (int i = 0; i < nofCasesPlusDefault; i++) { |
4960 if (i < nofCases) { |
4846 if (i < nofCases) { |
4961 keys[i] = bs.keyAt(i); |
4847 keys[i] = bs.keyAt(i); |
4962 } |
4848 } |
4963 |
|
4964 if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) { |
4849 if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) { |
4965 if (deoptSuccessorIndex < 0) { |
4850 deoptSuccessorIndex = SWITCH_DEOPT_SEEN; |
4966 deoptSuccessorIndex = nextSuccessorIndex++; |
4851 keySuccessors[i] = SWITCH_DEOPT_SEEN; |
4967 actualSuccessors.add(null); |
|
4968 } |
|
4969 keySuccessors[i] = deoptSuccessorIndex; |
|
4970 } else { |
4852 } else { |
4971 int targetBci = i < nofCases ? bs.targetAt(i) : bs.defaultTarget(); |
4853 int targetBci = i < nofCases ? bs.targetAt(i) : bs.defaultTarget(); |
4972 SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci); |
4854 SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci); |
4973 if (info.actualIndex < 0) { |
4855 if (info.actualIndex < 0) { |
4974 info.actualIndex = nextSuccessorIndex++; |
4856 info.actualIndex = nextSuccessorIndex++; |
4999 * reaches a target, we have better chance cutting out unused branches. Otherwise, |
4881 * reaches a target, we have better chance cutting out unused branches. Otherwise, |
5000 * it might be beneficial routing to the same code instead of deopting. |
4882 * it might be beneficial routing to the same code instead of deopting. |
5001 * |
4883 * |
5002 * The following code rewires deoptimization stub to existing resolved branch target if |
4884 * The following code rewires deoptimization stub to existing resolved branch target if |
5003 * the target is connected by more than 1 cases. |
4885 * the target is connected by more than 1 cases. |
4886 * |
|
4887 * If this operation rewires every deoptimization seen to an existing branch, care is |
|
4888 * taken that we do not spawn a branch that will never be taken. |
|
5004 */ |
4889 */ |
5005 if (deoptSuccessorIndex >= 0) { |
4890 if (deoptSuccessorIndex == SWITCH_DEOPT_SEEN) { |
5006 int[] connectedCases = new int[nextSuccessorIndex]; |
4891 int[] connectedCases = new int[nextSuccessorIndex + 1]; |
5007 for (int i = 0; i < nofCasesPlusDefault; i++) { |
4892 for (int i = 0; i < nofCasesPlusDefault; i++) { |
5008 connectedCases[keySuccessors[i]]++; |
4893 connectedCases[keySuccessors[i] + 1]++; |
5009 } |
4894 } |
5010 |
4895 |
5011 for (int i = 0; i < nofCasesPlusDefault; i++) { |
4896 for (int i = 0; i < nofCasesPlusDefault; i++) { |
5012 if (keySuccessors[i] == deoptSuccessorIndex) { |
4897 if (keySuccessors[i] == SWITCH_DEOPT_SEEN) { |
5013 int targetBci = i < nofCases ? bs.targetAt(i) : bs.defaultTarget(); |
4898 int targetBci = i < nofCases ? bs.targetAt(i) : bs.defaultTarget(); |
5014 SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci); |
4899 SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci); |
5015 int rewiredIndex = info.actualIndex; |
4900 int rewiredIndex = info.actualIndex; |
5016 if (rewiredIndex >= 0 && connectedCases[rewiredIndex] > 1) { |
4901 if (rewiredIndex >= 0 && connectedCases[rewiredIndex + 1] > 1) { |
4902 // Rewire |
|
5017 keySuccessors[i] = info.actualIndex; |
4903 keySuccessors[i] = info.actualIndex; |
4904 } else { |
|
4905 if (deoptSuccessorIndex == SWITCH_DEOPT_SEEN) { |
|
4906 // Spawn deopt successor if needed. |
|
4907 deoptSuccessorIndex = nextSuccessorIndex++; |
|
4908 actualSuccessors.add(null); |
|
4909 } |
|
4910 keySuccessors[i] = deoptSuccessorIndex; |
|
5018 } |
4911 } |
5019 } |
4912 } |
5020 } |
4913 } |
5021 } |
4914 } |
5022 |
4915 |
5216 case L2I : genNarrow(JavaKind.Long, JavaKind.Int); break; |
5109 case L2I : genNarrow(JavaKind.Long, JavaKind.Int); break; |
5217 case I2L : genSignExtend(JavaKind.Int, JavaKind.Long); break; |
5110 case I2L : genSignExtend(JavaKind.Int, JavaKind.Long); break; |
5218 case I2B : genSignExtend(JavaKind.Byte, JavaKind.Int); break; |
5111 case I2B : genSignExtend(JavaKind.Byte, JavaKind.Int); break; |
5219 case I2S : genSignExtend(JavaKind.Short, JavaKind.Int); break; |
5112 case I2S : genSignExtend(JavaKind.Short, JavaKind.Int); break; |
5220 case I2C : genZeroExtend(JavaKind.Char, JavaKind.Int); break; |
5113 case I2C : genZeroExtend(JavaKind.Char, JavaKind.Int); break; |
5221 case LCMP : genCompareOp(JavaKind.Long, false); break; |
5114 case LCMP : genIntegerCompareOp(JavaKind.Long); break; |
5222 case FCMPL : genCompareOp(JavaKind.Float, true); break; |
5115 case FCMPL : genFloatCompareOp(JavaKind.Float, true); break; |
5223 case FCMPG : genCompareOp(JavaKind.Float, false); break; |
5116 case FCMPG : genFloatCompareOp(JavaKind.Float, false); break; |
5224 case DCMPL : genCompareOp(JavaKind.Double, true); break; |
5117 case DCMPL : genFloatCompareOp(JavaKind.Double, true); break; |
5225 case DCMPG : genCompareOp(JavaKind.Double, false); break; |
5118 case DCMPG : genFloatCompareOp(JavaKind.Double, false); break; |
5226 case IFEQ : genIfZero(Condition.EQ); break; |
5119 case IFEQ : genIfZero(Condition.EQ); break; |
5227 case IFNE : genIfZero(Condition.NE); break; |
5120 case IFNE : genIfZero(Condition.NE); break; |
5228 case IFLT : genIfZero(Condition.LT); break; |
5121 case IFLT : genIfZero(Condition.LT); break; |
5229 case IFGE : genIfZero(Condition.GE); break; |
5122 case IFGE : genIfZero(Condition.GE); break; |
5230 case IFGT : genIfZero(Condition.GT); break; |
5123 case IFGT : genIfZero(Condition.GT); break; |
5348 |
5241 |
5349 static String nSpaces(int n) { |
5242 static String nSpaces(int n) { |
5350 return n == 0 ? "" : format("%" + n + "s", ""); |
5243 return n == 0 ? "" : format("%" + n + "s", ""); |
5351 } |
5244 } |
5352 } |
5245 } |
5353 |