BytecodeParser.java revision 12968:4d8a004e5c6d
1/* 2 * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23package org.graalvm.compiler.java; 24 25import static java.lang.String.format; 26import static java.lang.reflect.Modifier.STATIC; 27import static java.lang.reflect.Modifier.SYNCHRONIZED; 28import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile; 29import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile; 30import static jdk.vm.ci.meta.DeoptimizationReason.JavaSubroutineMismatch; 31import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException; 32import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint; 33import static jdk.vm.ci.meta.DeoptimizationReason.TypeCheckedInliningViolated; 34import static jdk.vm.ci.meta.DeoptimizationReason.UnreachedCode; 35import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved; 36import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI; 37import static org.graalvm.compiler.bytecode.Bytecodes.AALOAD; 38import static org.graalvm.compiler.bytecode.Bytecodes.AASTORE; 39import static org.graalvm.compiler.bytecode.Bytecodes.ACONST_NULL; 40import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD; 41import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_0; 42import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_1; 43import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_2; 44import static org.graalvm.compiler.bytecode.Bytecodes.ALOAD_3; 45import static org.graalvm.compiler.bytecode.Bytecodes.ANEWARRAY; 46import static org.graalvm.compiler.bytecode.Bytecodes.ARETURN; 47import static org.graalvm.compiler.bytecode.Bytecodes.ARRAYLENGTH; 48import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE; 49import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_0; 50import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_1; 51import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_2; 52import static org.graalvm.compiler.bytecode.Bytecodes.ASTORE_3; 53import static org.graalvm.compiler.bytecode.Bytecodes.ATHROW; 54import static org.graalvm.compiler.bytecode.Bytecodes.BALOAD; 55import static org.graalvm.compiler.bytecode.Bytecodes.BASTORE; 56import static org.graalvm.compiler.bytecode.Bytecodes.BIPUSH; 57import static org.graalvm.compiler.bytecode.Bytecodes.BREAKPOINT; 58import static org.graalvm.compiler.bytecode.Bytecodes.CALOAD; 59import static org.graalvm.compiler.bytecode.Bytecodes.CASTORE; 60import static org.graalvm.compiler.bytecode.Bytecodes.CHECKCAST; 61import static org.graalvm.compiler.bytecode.Bytecodes.D2F; 62import static org.graalvm.compiler.bytecode.Bytecodes.D2I; 63import static org.graalvm.compiler.bytecode.Bytecodes.D2L; 64import static org.graalvm.compiler.bytecode.Bytecodes.DADD; 65import static org.graalvm.compiler.bytecode.Bytecodes.DALOAD; 66import static org.graalvm.compiler.bytecode.Bytecodes.DASTORE; 67import static org.graalvm.compiler.bytecode.Bytecodes.DCMPG; 68import static org.graalvm.compiler.bytecode.Bytecodes.DCMPL; 69import static org.graalvm.compiler.bytecode.Bytecodes.DCONST_0; 70import static org.graalvm.compiler.bytecode.Bytecodes.DCONST_1; 71import static org.graalvm.compiler.bytecode.Bytecodes.DDIV; 72import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD; 73import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_0; 74import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_1; 75import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_2; 76import static org.graalvm.compiler.bytecode.Bytecodes.DLOAD_3; 77import static org.graalvm.compiler.bytecode.Bytecodes.DMUL; 78import static org.graalvm.compiler.bytecode.Bytecodes.DNEG; 79import static org.graalvm.compiler.bytecode.Bytecodes.DREM; 80import static org.graalvm.compiler.bytecode.Bytecodes.DRETURN; 81import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE; 82import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_0; 83import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_1; 84import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_2; 85import static org.graalvm.compiler.bytecode.Bytecodes.DSTORE_3; 86import static org.graalvm.compiler.bytecode.Bytecodes.DSUB; 87import static org.graalvm.compiler.bytecode.Bytecodes.DUP; 88import static org.graalvm.compiler.bytecode.Bytecodes.DUP2; 89import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X1; 90import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X2; 91import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X1; 92import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X2; 93import static org.graalvm.compiler.bytecode.Bytecodes.F2D; 94import static org.graalvm.compiler.bytecode.Bytecodes.F2I; 95import static org.graalvm.compiler.bytecode.Bytecodes.F2L; 96import static org.graalvm.compiler.bytecode.Bytecodes.FADD; 97import static org.graalvm.compiler.bytecode.Bytecodes.FALOAD; 98import static org.graalvm.compiler.bytecode.Bytecodes.FASTORE; 99import static org.graalvm.compiler.bytecode.Bytecodes.FCMPG; 100import static org.graalvm.compiler.bytecode.Bytecodes.FCMPL; 101import static org.graalvm.compiler.bytecode.Bytecodes.FCONST_0; 102import static org.graalvm.compiler.bytecode.Bytecodes.FCONST_1; 103import static org.graalvm.compiler.bytecode.Bytecodes.FCONST_2; 104import static org.graalvm.compiler.bytecode.Bytecodes.FDIV; 105import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD; 106import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_0; 107import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_1; 108import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_2; 109import static org.graalvm.compiler.bytecode.Bytecodes.FLOAD_3; 110import static org.graalvm.compiler.bytecode.Bytecodes.FMUL; 111import static org.graalvm.compiler.bytecode.Bytecodes.FNEG; 112import static org.graalvm.compiler.bytecode.Bytecodes.FREM; 113import static org.graalvm.compiler.bytecode.Bytecodes.FRETURN; 114import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE; 115import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_0; 116import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_1; 117import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_2; 118import static org.graalvm.compiler.bytecode.Bytecodes.FSTORE_3; 119import static org.graalvm.compiler.bytecode.Bytecodes.FSUB; 120import static org.graalvm.compiler.bytecode.Bytecodes.GETFIELD; 121import static org.graalvm.compiler.bytecode.Bytecodes.GETSTATIC; 122import static org.graalvm.compiler.bytecode.Bytecodes.GOTO; 123import static org.graalvm.compiler.bytecode.Bytecodes.GOTO_W; 124import static org.graalvm.compiler.bytecode.Bytecodes.I2B; 125import static org.graalvm.compiler.bytecode.Bytecodes.I2C; 126import static org.graalvm.compiler.bytecode.Bytecodes.I2D; 127import static org.graalvm.compiler.bytecode.Bytecodes.I2F; 128import static org.graalvm.compiler.bytecode.Bytecodes.I2L; 129import static org.graalvm.compiler.bytecode.Bytecodes.I2S; 130import static org.graalvm.compiler.bytecode.Bytecodes.IADD; 131import static org.graalvm.compiler.bytecode.Bytecodes.IALOAD; 132import static org.graalvm.compiler.bytecode.Bytecodes.IAND; 133import static org.graalvm.compiler.bytecode.Bytecodes.IASTORE; 134import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_0; 135import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_1; 136import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_2; 137import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_3; 138import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_4; 139import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_5; 140import static org.graalvm.compiler.bytecode.Bytecodes.ICONST_M1; 141import static org.graalvm.compiler.bytecode.Bytecodes.IDIV; 142import static org.graalvm.compiler.bytecode.Bytecodes.IFEQ; 143import static org.graalvm.compiler.bytecode.Bytecodes.IFGE; 144import static org.graalvm.compiler.bytecode.Bytecodes.IFGT; 145import static org.graalvm.compiler.bytecode.Bytecodes.IFLE; 146import static org.graalvm.compiler.bytecode.Bytecodes.IFLT; 147import static org.graalvm.compiler.bytecode.Bytecodes.IFNE; 148import static org.graalvm.compiler.bytecode.Bytecodes.IFNONNULL; 149import static org.graalvm.compiler.bytecode.Bytecodes.IFNULL; 150import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPEQ; 151import static org.graalvm.compiler.bytecode.Bytecodes.IF_ACMPNE; 152import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPEQ; 153import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGE; 154import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPGT; 155import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLE; 156import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPLT; 157import static org.graalvm.compiler.bytecode.Bytecodes.IF_ICMPNE; 158import static org.graalvm.compiler.bytecode.Bytecodes.IINC; 159import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD; 160import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_0; 161import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_1; 162import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_2; 163import static org.graalvm.compiler.bytecode.Bytecodes.ILOAD_3; 164import static org.graalvm.compiler.bytecode.Bytecodes.IMUL; 165import static org.graalvm.compiler.bytecode.Bytecodes.INEG; 166import static org.graalvm.compiler.bytecode.Bytecodes.INSTANCEOF; 167import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEDYNAMIC; 168import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEINTERFACE; 169import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESPECIAL; 170import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESTATIC; 171import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEVIRTUAL; 172import static org.graalvm.compiler.bytecode.Bytecodes.IOR; 173import static org.graalvm.compiler.bytecode.Bytecodes.IREM; 174import static org.graalvm.compiler.bytecode.Bytecodes.IRETURN; 175import static org.graalvm.compiler.bytecode.Bytecodes.ISHL; 176import static org.graalvm.compiler.bytecode.Bytecodes.ISHR; 177import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE; 178import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_0; 179import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_1; 180import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_2; 181import static org.graalvm.compiler.bytecode.Bytecodes.ISTORE_3; 182import static org.graalvm.compiler.bytecode.Bytecodes.ISUB; 183import static org.graalvm.compiler.bytecode.Bytecodes.IUSHR; 184import static org.graalvm.compiler.bytecode.Bytecodes.IXOR; 185import static org.graalvm.compiler.bytecode.Bytecodes.JSR; 186import static org.graalvm.compiler.bytecode.Bytecodes.JSR_W; 187import static org.graalvm.compiler.bytecode.Bytecodes.L2D; 188import static org.graalvm.compiler.bytecode.Bytecodes.L2F; 189import static org.graalvm.compiler.bytecode.Bytecodes.L2I; 190import static org.graalvm.compiler.bytecode.Bytecodes.LADD; 191import static org.graalvm.compiler.bytecode.Bytecodes.LALOAD; 192import static org.graalvm.compiler.bytecode.Bytecodes.LAND; 193import static org.graalvm.compiler.bytecode.Bytecodes.LASTORE; 194import static org.graalvm.compiler.bytecode.Bytecodes.LCMP; 195import static org.graalvm.compiler.bytecode.Bytecodes.LCONST_0; 196import static org.graalvm.compiler.bytecode.Bytecodes.LCONST_1; 197import static org.graalvm.compiler.bytecode.Bytecodes.LDC; 198import static org.graalvm.compiler.bytecode.Bytecodes.LDC2_W; 199import static org.graalvm.compiler.bytecode.Bytecodes.LDC_W; 200import static org.graalvm.compiler.bytecode.Bytecodes.LDIV; 201import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD; 202import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_0; 203import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_1; 204import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_2; 205import static org.graalvm.compiler.bytecode.Bytecodes.LLOAD_3; 206import static org.graalvm.compiler.bytecode.Bytecodes.LMUL; 207import static org.graalvm.compiler.bytecode.Bytecodes.LNEG; 208import static org.graalvm.compiler.bytecode.Bytecodes.LOOKUPSWITCH; 209import static org.graalvm.compiler.bytecode.Bytecodes.LOR; 210import static org.graalvm.compiler.bytecode.Bytecodes.LREM; 211import static org.graalvm.compiler.bytecode.Bytecodes.LRETURN; 212import static org.graalvm.compiler.bytecode.Bytecodes.LSHL; 213import static org.graalvm.compiler.bytecode.Bytecodes.LSHR; 214import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE; 215import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_0; 216import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_1; 217import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_2; 218import static org.graalvm.compiler.bytecode.Bytecodes.LSTORE_3; 219import static org.graalvm.compiler.bytecode.Bytecodes.LSUB; 220import static org.graalvm.compiler.bytecode.Bytecodes.LUSHR; 221import static org.graalvm.compiler.bytecode.Bytecodes.LXOR; 222import static org.graalvm.compiler.bytecode.Bytecodes.MONITORENTER; 223import static org.graalvm.compiler.bytecode.Bytecodes.MONITOREXIT; 224import static org.graalvm.compiler.bytecode.Bytecodes.MULTIANEWARRAY; 225import static org.graalvm.compiler.bytecode.Bytecodes.NEW; 226import static org.graalvm.compiler.bytecode.Bytecodes.NEWARRAY; 227import static org.graalvm.compiler.bytecode.Bytecodes.NOP; 228import static org.graalvm.compiler.bytecode.Bytecodes.POP; 229import static org.graalvm.compiler.bytecode.Bytecodes.POP2; 230import static org.graalvm.compiler.bytecode.Bytecodes.PUTFIELD; 231import static org.graalvm.compiler.bytecode.Bytecodes.PUTSTATIC; 232import static org.graalvm.compiler.bytecode.Bytecodes.RET; 233import static org.graalvm.compiler.bytecode.Bytecodes.RETURN; 234import static org.graalvm.compiler.bytecode.Bytecodes.SALOAD; 235import static org.graalvm.compiler.bytecode.Bytecodes.SASTORE; 236import static org.graalvm.compiler.bytecode.Bytecodes.SIPUSH; 237import static org.graalvm.compiler.bytecode.Bytecodes.SWAP; 238import static org.graalvm.compiler.bytecode.Bytecodes.TABLESWITCH; 239import static org.graalvm.compiler.bytecode.Bytecodes.nameOf; 240import static org.graalvm.compiler.core.common.GraalOptions.DeoptALot; 241import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; 242import static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining; 243import static org.graalvm.compiler.core.common.GraalOptions.PrintProfilingInformation; 244import static org.graalvm.compiler.core.common.GraalOptions.ResolveClassBeforeStaticInvoke; 245import static org.graalvm.compiler.core.common.GraalOptions.StressExplicitExceptionCode; 246import static org.graalvm.compiler.core.common.GraalOptions.StressInvokeWithExceptionNode; 247import static org.graalvm.compiler.core.common.type.StampFactory.objectNonNull; 248import static org.graalvm.compiler.debug.GraalError.guarantee; 249import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; 250import static org.graalvm.compiler.java.BytecodeParserOptions.DumpDuringGraphBuilding; 251import static org.graalvm.compiler.java.BytecodeParserOptions.TraceBytecodeParserLevel; 252import static org.graalvm.compiler.java.BytecodeParserOptions.TraceInlineDuringParsing; 253import static org.graalvm.compiler.java.BytecodeParserOptions.TraceParserPlugins; 254import static org.graalvm.compiler.java.BytecodeParserOptions.UseGuardedIntrinsics; 255import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_DURING_PARSING; 256import static org.graalvm.compiler.nodes.type.StampTool.isPointerNonNull; 257 258import java.util.ArrayList; 259import java.util.Collections; 260import java.util.Comparator; 261import java.util.Formatter; 262import java.util.List; 263 264import org.graalvm.compiler.bytecode.Bytecode; 265import org.graalvm.compiler.bytecode.BytecodeDisassembler; 266import org.graalvm.compiler.bytecode.BytecodeLookupSwitch; 267import org.graalvm.compiler.bytecode.BytecodeProvider; 268import org.graalvm.compiler.bytecode.BytecodeStream; 269import org.graalvm.compiler.bytecode.BytecodeSwitch; 270import org.graalvm.compiler.bytecode.BytecodeTableSwitch; 271import org.graalvm.compiler.bytecode.Bytecodes; 272import org.graalvm.compiler.bytecode.Bytes; 273import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; 274import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider; 275import org.graalvm.compiler.core.common.PermanentBailoutException; 276import org.graalvm.compiler.core.common.LocationIdentity; 277import org.graalvm.compiler.core.common.calc.Condition; 278import org.graalvm.compiler.core.common.calc.FloatConvert; 279import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; 280import org.graalvm.compiler.core.common.type.ObjectStamp; 281import org.graalvm.compiler.core.common.type.Stamp; 282import org.graalvm.compiler.core.common.type.StampFactory; 283import org.graalvm.compiler.core.common.type.StampPair; 284import org.graalvm.compiler.core.common.type.TypeReference; 285import org.graalvm.compiler.core.common.util.Util; 286import org.graalvm.compiler.debug.Assertions; 287import org.graalvm.compiler.debug.Debug; 288import org.graalvm.compiler.debug.Debug.Scope; 289import org.graalvm.compiler.debug.DebugCloseable; 290import org.graalvm.compiler.debug.DebugCounter; 291import org.graalvm.compiler.debug.GraalError; 292import org.graalvm.compiler.debug.Indent; 293import org.graalvm.compiler.debug.TTY; 294import org.graalvm.compiler.graph.Graph.Mark; 295import org.graalvm.compiler.graph.Node; 296import org.graalvm.compiler.graph.NodeSourcePosition; 297import org.graalvm.compiler.graph.iterators.NodeIterable; 298import org.graalvm.compiler.java.BciBlockMapping.BciBlock; 299import org.graalvm.compiler.java.BciBlockMapping.ExceptionDispatchBlock; 300import org.graalvm.compiler.nodes.AbstractBeginNode; 301import org.graalvm.compiler.nodes.AbstractMergeNode; 302import org.graalvm.compiler.nodes.BeginNode; 303import org.graalvm.compiler.nodes.BeginStateSplitNode; 304import org.graalvm.compiler.nodes.CallTargetNode; 305import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; 306import org.graalvm.compiler.nodes.ConstantNode; 307import org.graalvm.compiler.nodes.ControlSplitNode; 308import org.graalvm.compiler.nodes.DeoptimizeNode; 309import org.graalvm.compiler.nodes.EndNode; 310import org.graalvm.compiler.nodes.EntryMarkerNode; 311import org.graalvm.compiler.nodes.EntryProxyNode; 312import org.graalvm.compiler.nodes.FieldLocationIdentity; 313import org.graalvm.compiler.nodes.FixedGuardNode; 314import org.graalvm.compiler.nodes.FixedNode; 315import org.graalvm.compiler.nodes.FixedWithNextNode; 316import org.graalvm.compiler.nodes.FrameState; 317import org.graalvm.compiler.nodes.FullInfopointNode; 318import org.graalvm.compiler.nodes.IfNode; 319import org.graalvm.compiler.nodes.Invoke; 320import org.graalvm.compiler.nodes.InvokeNode; 321import org.graalvm.compiler.nodes.InvokeWithExceptionNode; 322import org.graalvm.compiler.nodes.KillingBeginNode; 323import org.graalvm.compiler.nodes.LogicConstantNode; 324import org.graalvm.compiler.nodes.LogicNegationNode; 325import org.graalvm.compiler.nodes.LogicNode; 326import org.graalvm.compiler.nodes.LoopBeginNode; 327import org.graalvm.compiler.nodes.LoopEndNode; 328import org.graalvm.compiler.nodes.LoopExitNode; 329import org.graalvm.compiler.nodes.MergeNode; 330import org.graalvm.compiler.nodes.ParameterNode; 331import org.graalvm.compiler.nodes.PiNode; 332import org.graalvm.compiler.nodes.ReturnNode; 333import org.graalvm.compiler.nodes.StartNode; 334import org.graalvm.compiler.nodes.StateSplit; 335import org.graalvm.compiler.nodes.StructuredGraph; 336import org.graalvm.compiler.nodes.UnwindNode; 337import org.graalvm.compiler.nodes.ValueNode; 338import org.graalvm.compiler.nodes.calc.AddNode; 339import org.graalvm.compiler.nodes.calc.AndNode; 340import org.graalvm.compiler.nodes.calc.CompareNode; 341import org.graalvm.compiler.nodes.calc.ConditionalNode; 342import org.graalvm.compiler.nodes.calc.DivNode; 343import org.graalvm.compiler.nodes.calc.FloatConvertNode; 344import org.graalvm.compiler.nodes.calc.IntegerBelowNode; 345import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; 346import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; 347import org.graalvm.compiler.nodes.calc.IsNullNode; 348import org.graalvm.compiler.nodes.calc.LeftShiftNode; 349import org.graalvm.compiler.nodes.calc.MulNode; 350import org.graalvm.compiler.nodes.calc.NarrowNode; 351import org.graalvm.compiler.nodes.calc.NegateNode; 352import org.graalvm.compiler.nodes.calc.NormalizeCompareNode; 353import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; 354import org.graalvm.compiler.nodes.calc.OrNode; 355import org.graalvm.compiler.nodes.calc.RemNode; 356import org.graalvm.compiler.nodes.calc.RightShiftNode; 357import org.graalvm.compiler.nodes.calc.SignExtendNode; 358import org.graalvm.compiler.nodes.calc.SignedDivNode; 359import org.graalvm.compiler.nodes.calc.SignedRemNode; 360import org.graalvm.compiler.nodes.calc.SubNode; 361import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode; 362import org.graalvm.compiler.nodes.calc.XorNode; 363import org.graalvm.compiler.nodes.calc.ZeroExtendNode; 364import org.graalvm.compiler.nodes.extended.AnchoringNode; 365import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode; 366import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; 367import org.graalvm.compiler.nodes.extended.LoadHubNode; 368import org.graalvm.compiler.nodes.extended.LoadMethodNode; 369import org.graalvm.compiler.nodes.extended.MembarNode; 370import org.graalvm.compiler.nodes.extended.ValueAnchorNode; 371import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin; 372import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; 373import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; 374import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; 375import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; 376import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo; 377import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; 378import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; 379import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver; 380import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; 381import org.graalvm.compiler.nodes.graphbuilderconf.ProfilingPlugin; 382import org.graalvm.compiler.nodes.java.ArrayLengthNode; 383import org.graalvm.compiler.nodes.java.ExceptionObjectNode; 384import org.graalvm.compiler.nodes.java.FinalFieldBarrierNode; 385import org.graalvm.compiler.nodes.java.InstanceOfNode; 386import org.graalvm.compiler.nodes.java.LoadFieldNode; 387import org.graalvm.compiler.nodes.java.LoadIndexedNode; 388import org.graalvm.compiler.nodes.java.MethodCallTargetNode; 389import org.graalvm.compiler.nodes.java.MonitorEnterNode; 390import org.graalvm.compiler.nodes.java.MonitorExitNode; 391import org.graalvm.compiler.nodes.java.MonitorIdNode; 392import org.graalvm.compiler.nodes.java.NewArrayNode; 393import org.graalvm.compiler.nodes.java.NewInstanceNode; 394import org.graalvm.compiler.nodes.java.NewMultiArrayNode; 395import org.graalvm.compiler.nodes.java.RegisterFinalizerNode; 396import org.graalvm.compiler.nodes.java.StoreFieldNode; 397import org.graalvm.compiler.nodes.java.StoreIndexedNode; 398import org.graalvm.compiler.nodes.spi.StampProvider; 399import org.graalvm.compiler.nodes.type.StampTool; 400import org.graalvm.compiler.nodes.util.GraphUtil; 401import org.graalvm.compiler.options.OptionValues; 402import org.graalvm.compiler.phases.OptimisticOptimizations; 403import org.graalvm.util.EconomicMap; 404import org.graalvm.util.Equivalence; 405 406import jdk.vm.ci.code.BailoutException; 407import jdk.vm.ci.code.BytecodeFrame; 408import jdk.vm.ci.code.CodeUtil; 409import jdk.vm.ci.code.site.InfopointReason; 410import jdk.vm.ci.meta.ConstantPool; 411import jdk.vm.ci.meta.ConstantReflectionProvider; 412import jdk.vm.ci.meta.DeoptimizationAction; 413import jdk.vm.ci.meta.DeoptimizationReason; 414import jdk.vm.ci.meta.JavaConstant; 415import jdk.vm.ci.meta.JavaField; 416import jdk.vm.ci.meta.JavaKind; 417import jdk.vm.ci.meta.JavaMethod; 418import jdk.vm.ci.meta.JavaType; 419import jdk.vm.ci.meta.JavaTypeProfile; 420import jdk.vm.ci.meta.JavaTypeProfile.ProfiledType; 421import jdk.vm.ci.meta.LineNumberTable; 422import jdk.vm.ci.meta.MetaAccessProvider; 423import jdk.vm.ci.meta.ProfilingInfo; 424import jdk.vm.ci.meta.RawConstant; 425import jdk.vm.ci.meta.ResolvedJavaField; 426import jdk.vm.ci.meta.ResolvedJavaMethod; 427import jdk.vm.ci.meta.ResolvedJavaType; 428import jdk.vm.ci.meta.TriState; 429 430/** 431 * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. 432 */ 433public class BytecodeParser implements GraphBuilderContext { 434 435 /** 436 * The minimum value to which {@link BytecodeParserOptions#TraceBytecodeParserLevel} must be set 437 * to trace the bytecode instructions as they are parsed. 438 */ 439 public static final int TRACELEVEL_INSTRUCTIONS = 1; 440 441 /** 442 * The minimum value to which {@link BytecodeParserOptions#TraceBytecodeParserLevel} must be set 443 * to trace the frame state before each bytecode instruction as it is parsed. 444 */ 445 public static final int TRACELEVEL_STATE = 2; 446 447 /** 448 * Meters the number of actual bytecodes parsed. 449 */ 450 public static final DebugCounter BytecodesParsed = Debug.counter("BytecodesParsed"); 451 452 protected static final DebugCounter EXPLICIT_EXCEPTIONS = Debug.counter("ExplicitExceptions"); 453 454 /** 455 * A scoped object for tasks to be performed after parsing an intrinsic such as processing 456 * {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frames states. 457 */ 458 static class IntrinsicScope implements AutoCloseable { 459 FrameState stateBefore; 460 final Mark mark; 461 final BytecodeParser parser; 462 463 /** 464 * Creates a scope for root parsing an intrinsic. 465 * 466 * @param parser the parsing context of the intrinsic 467 */ 468 IntrinsicScope(BytecodeParser parser) { 469 this.parser = parser; 470 assert parser.parent == null; 471 assert parser.bci() == 0; 472 mark = null; 473 } 474 475 /** 476 * Creates a scope for parsing an intrinsic during graph builder inlining. 477 * 478 * @param parser the parsing context of the (non-intrinsic) method calling the intrinsic 479 * @param args the arguments to the call 480 */ 481 IntrinsicScope(BytecodeParser parser, JavaKind[] argSlotKinds, ValueNode[] args) { 482 assert !parser.parsingIntrinsic(); 483 this.parser = parser; 484 mark = parser.getGraph().getMark(); 485 stateBefore = parser.frameState.create(parser.bci(), parser.getNonIntrinsicAncestor(), false, argSlotKinds, args); 486 } 487 488 @Override 489 public void close() { 490 IntrinsicContext intrinsic = parser.intrinsicContext; 491 if (intrinsic != null && intrinsic.isPostParseInlined()) { 492 return; 493 } 494 495 processPlaceholderFrameStates(intrinsic); 496 } 497 498 /** 499 * Fixes up the {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frame states 500 * added to the graph while parsing/inlining the intrinsic for which this object exists. 501 */ 502 private void processPlaceholderFrameStates(IntrinsicContext intrinsic) { 503 FrameState stateAfterReturn = null; 504 StructuredGraph graph = parser.getGraph(); 505 for (Node node : graph.getNewNodes(mark)) { 506 if (node instanceof FrameState) { 507 FrameState frameState = (FrameState) node; 508 if (BytecodeFrame.isPlaceholderBci(frameState.bci)) { 509 if (frameState.bci == BytecodeFrame.AFTER_BCI) { 510 FrameStateBuilder frameStateBuilder = parser.frameState; 511 if (frameState.stackSize() != 0) { 512 assert frameState.usages().count() == 1; 513 ValueNode returnVal = frameState.stackAt(0); 514 assert returnVal == frameState.usages().first(); 515 516 if (parser.currentInvokeReturnType == null) { 517 assert intrinsic.isCompilationRoot(); 518 FrameState newFrameState = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI)); 519 frameState.replaceAndDelete(newFrameState); 520 } else { 521 /* 522 * Swap the top-of-stack value with the side-effect return value 523 * using the frame state. 524 */ 525 JavaKind returnKind = parser.currentInvokeReturnType.getJavaKind(); 526 ValueNode tos = frameStateBuilder.pop(returnKind); 527 assert tos.getStackKind() == returnVal.getStackKind(); 528 FrameState newFrameState = frameStateBuilder.create(parser.stream.nextBCI(), parser.getNonIntrinsicAncestor(), false, new JavaKind[]{returnKind}, 529 new ValueNode[]{returnVal}); 530 frameState.replaceAndDelete(newFrameState); 531 frameStateBuilder.push(returnKind, tos); 532 } 533 } else { 534 if (stateAfterReturn == null) { 535 if (intrinsic != null) { 536 assert intrinsic.isCompilationRoot(); 537 stateAfterReturn = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI)); 538 } else { 539 stateAfterReturn = frameStateBuilder.create(parser.stream.nextBCI(), null); 540 } 541 } 542 frameState.replaceAndDelete(stateAfterReturn); 543 } 544 } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) { 545 if (stateBefore == null) { 546 stateBefore = graph.start().stateAfter(); 547 } 548 if (stateBefore != frameState) { 549 frameState.replaceAndDelete(stateBefore); 550 } 551 } else { 552 assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI; 553 } 554 } 555 } 556 } 557 } 558 } 559 560 private static class Target { 561 FixedNode fixed; 562 FrameStateBuilder state; 563 564 Target(FixedNode fixed, FrameStateBuilder state) { 565 this.fixed = fixed; 566 this.state = state; 567 } 568 } 569 570 @SuppressWarnings("serial") 571 public static class BytecodeParserError extends GraalError { 572 573 public BytecodeParserError(Throwable cause) { 574 super(cause); 575 } 576 577 public BytecodeParserError(String msg, Object... args) { 578 super(msg, args); 579 } 580 } 581 582 private final GraphBuilderPhase.Instance graphBuilderInstance; 583 protected final StructuredGraph graph; 584 protected final OptionValues options; 585 586 private BciBlockMapping blockMap; 587 private LocalLiveness liveness; 588 protected final int entryBCI; 589 private final BytecodeParser parent; 590 591 private LineNumberTable lnt; 592 private int previousLineNumber; 593 private int currentLineNumber; 594 595 private ValueNode methodSynchronizedObject; 596 597 private ValueNode returnValue; 598 private FixedWithNextNode beforeReturnNode; 599 private ValueNode unwindValue; 600 private FixedWithNextNode beforeUnwindNode; 601 602 protected FixedWithNextNode lastInstr; // the last instruction added 603 private boolean controlFlowSplit; 604 private final InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(this); 605 606 private FixedWithNextNode[] firstInstructionArray; 607 private FrameStateBuilder[] entryStateArray; 608 609 private boolean finalBarrierRequired; 610 private ValueNode originalReceiver; 611 612 protected BytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, 613 int entryBCI, IntrinsicContext intrinsicContext) { 614 this.bytecodeProvider = intrinsicContext == null ? new ResolvedJavaMethodBytecodeProvider() : intrinsicContext.getBytecodeProvider(); 615 this.code = bytecodeProvider.getBytecode(method); 616 this.method = code.getMethod(); 617 this.graphBuilderInstance = graphBuilderInstance; 618 this.graph = graph; 619 this.options = graph.getOptions(); 620 this.graphBuilderConfig = graphBuilderInstance.graphBuilderConfig; 621 this.optimisticOpts = graphBuilderInstance.optimisticOpts; 622 this.metaAccess = graphBuilderInstance.metaAccess; 623 this.stampProvider = graphBuilderInstance.stampProvider; 624 this.constantReflection = graphBuilderInstance.constantReflection; 625 this.constantFieldProvider = graphBuilderInstance.constantFieldProvider; 626 this.stream = new BytecodeStream(code.getCode()); 627 this.profilingInfo = graph.useProfilingInfo() ? code.getProfilingInfo() : null; 628 this.constantPool = code.getConstantPool(); 629 this.intrinsicContext = intrinsicContext; 630 this.entryBCI = entryBCI; 631 this.parent = parent; 632 633 assert code.getCode() != null : "method must contain bytecodes: " + method; 634 635 if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) { 636 lnt = code.getLineNumberTable(); 637 previousLineNumber = -1; 638 } 639 } 640 641 protected GraphBuilderPhase.Instance getGraphBuilderInstance() { 642 return graphBuilderInstance; 643 } 644 645 public ValueNode getReturnValue() { 646 return returnValue; 647 } 648 649 public FixedWithNextNode getBeforeReturnNode() { 650 return this.beforeReturnNode; 651 } 652 653 public ValueNode getUnwindValue() { 654 return unwindValue; 655 } 656 657 public FixedWithNextNode getBeforeUnwindNode() { 658 return this.beforeUnwindNode; 659 } 660 661 @SuppressWarnings("try") 662 protected void buildRootMethod() { 663 FrameStateBuilder startFrameState = new FrameStateBuilder(this, code, graph); 664 startFrameState.initializeForMethodStart(graph.getAssumptions(), graphBuilderConfig.eagerResolving() || intrinsicContext != null, graphBuilderConfig.getPlugins()); 665 666 try (IntrinsicScope s = intrinsicContext != null ? new IntrinsicScope(this) : null) { 667 build(graph.start(), startFrameState); 668 } 669 670 cleanupFinalGraph(); 671 ComputeLoopFrequenciesClosure.compute(graph); 672 } 673 674 @SuppressWarnings("try") 675 protected void build(FixedWithNextNode startInstruction, FrameStateBuilder startFrameState) { 676 if (PrintProfilingInformation.getValue(options) && profilingInfo != null) { 677 TTY.println("Profiling info for " + method.format("%H.%n(%p)")); 678 TTY.println(Util.indent(profilingInfo.toString(method, CodeUtil.NEW_LINE), " ")); 679 } 680 681 try (Indent indent = Debug.logAndIndent("build graph for %s", method)) { 682 if (bytecodeProvider.shouldRecordMethodDependencies()) { 683 assert getParent() != null || method.equals(graph.method()); 684 // Record method dependency in the graph 685 graph.recordMethod(method); 686 } 687 688 // compute the block map, setup exception handlers and get the entrypoint(s) 689 BciBlockMapping newMapping = BciBlockMapping.create(stream, code, options); 690 this.blockMap = newMapping; 691 this.firstInstructionArray = new FixedWithNextNode[blockMap.getBlockCount()]; 692 this.entryStateArray = new FrameStateBuilder[blockMap.getBlockCount()]; 693 if (!method.isStatic()) { 694 originalReceiver = startFrameState.loadLocal(0, JavaKind.Object); 695 } 696 697 /* 698 * Configure the assertion checking behavior of the FrameStateBuilder. This needs to be 699 * done only when assertions are enabled, so it is wrapped in an assertion itself. 700 */ 701 assert computeKindVerification(startFrameState); 702 703 try (Scope s = Debug.scope("LivenessAnalysis")) { 704 int maxLocals = method.getMaxLocals(); 705 liveness = LocalLiveness.compute(stream, blockMap.getBlocks(), maxLocals, blockMap.getLoopCount()); 706 } catch (Throwable e) { 707 throw Debug.handle(e); 708 } 709 710 lastInstr = startInstruction; 711 this.setCurrentFrameState(startFrameState); 712 stream.setBCI(0); 713 714 BciBlock startBlock = blockMap.getStartBlock(); 715 if (this.parent == null) { 716 StartNode startNode = graph.start(); 717 if (method.isSynchronized()) { 718 assert !parsingIntrinsic(); 719 startNode.setStateAfter(createFrameState(BytecodeFrame.BEFORE_BCI, startNode)); 720 } else { 721 if (!parsingIntrinsic()) { 722 if (graph.method() != null && graph.method().isJavaLangObjectInit()) { 723 /* 724 * Don't clear the receiver when Object.<init> is the compilation root. 725 * The receiver is needed as input to RegisterFinalizerNode. 726 */ 727 } else { 728 frameState.clearNonLiveLocals(startBlock, liveness, true); 729 } 730 assert bci() == 0; 731 startNode.setStateAfter(createFrameState(bci(), startNode)); 732 } else { 733 if (startNode.stateAfter() == null) { 734 FrameState stateAfterStart = createStateAfterStartOfReplacementGraph(); 735 startNode.setStateAfter(stateAfterStart); 736 } 737 } 738 } 739 } 740 741 if (method.isSynchronized()) { 742 finishPrepare(lastInstr, BytecodeFrame.BEFORE_BCI); 743 744 // add a monitor enter to the start block 745 methodSynchronizedObject = synchronizedObject(frameState, method); 746 frameState.clearNonLiveLocals(startBlock, liveness, true); 747 assert bci() == 0; 748 genMonitorEnter(methodSynchronizedObject, bci()); 749 } 750 751 ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin(); 752 if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { 753 FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); 754 profilingPlugin.profileInvoke(this, method, stateBefore); 755 } 756 757 finishPrepare(lastInstr, 0); 758 759 genInfoPointNode(InfopointReason.METHOD_START, null); 760 761 currentBlock = blockMap.getStartBlock(); 762 setEntryState(startBlock, frameState); 763 if (startBlock.isLoopHeader) { 764 appendGoto(startBlock); 765 } else { 766 setFirstInstruction(startBlock, lastInstr); 767 } 768 769 BciBlock[] blocks = blockMap.getBlocks(); 770 for (BciBlock block : blocks) { 771 processBlock(block); 772 } 773 774 if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL) && DumpDuringGraphBuilding.getValue(options) && this.beforeReturnNode != startInstruction) { 775 Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Bytecodes parsed: %s.%s", method.getDeclaringClass().getUnqualifiedName(), method.getName()); 776 } 777 } 778 } 779 780 private boolean computeKindVerification(FrameStateBuilder startFrameState) { 781 if (blockMap.hasJsrBytecodes) { 782 /* 783 * The JSR return address is an int value, but stored using the astore bytecode. Instead 784 * of weakening the kind assertion checking for all methods, we disable it completely 785 * for methods that contain a JSR bytecode. 786 */ 787 startFrameState.disableKindVerification(); 788 } 789 790 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 791 if (plugin.canChangeStackKind(this)) { 792 /* 793 * We have a plugin that can change the kind of values, so no kind assertion 794 * checking is possible. 795 */ 796 startFrameState.disableKindVerification(); 797 } 798 } 799 return true; 800 } 801 802 /** 803 * Hook for subclasses to modify synthetic code (start nodes and unwind nodes). 804 * 805 * @param instruction the current last instruction 806 * @param bci the current bci 807 */ 808 protected void finishPrepare(FixedWithNextNode instruction, int bci) { 809 } 810 811 protected void cleanupFinalGraph() { 812 GraphUtil.normalizeLoops(graph); 813 814 // Remove dead parameters. 815 for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { 816 if (param.hasNoUsages()) { 817 assert param.inputs().isEmpty(); 818 param.safeDelete(); 819 } 820 } 821 822 // Remove redundant begin nodes. 823 for (BeginNode beginNode : graph.getNodes(BeginNode.TYPE)) { 824 Node predecessor = beginNode.predecessor(); 825 if (predecessor instanceof ControlSplitNode) { 826 // The begin node is necessary. 827 } else if (!beginNode.hasUsages()) { 828 GraphUtil.unlinkFixedNode(beginNode); 829 beginNode.safeDelete(); 830 } 831 } 832 } 833 834 /** 835 * Creates the frame state after the start node of a graph for an {@link IntrinsicContext 836 * intrinsic} that is the parse root (either for root compiling or for post-parse inlining). 837 */ 838 private FrameState createStateAfterStartOfReplacementGraph() { 839 assert parent == null; 840 assert frameState.getMethod().equals(intrinsicContext.getIntrinsicMethod()); 841 assert bci() == 0; 842 assert frameState.stackSize() == 0; 843 FrameState stateAfterStart; 844 if (intrinsicContext.isPostParseInlined()) { 845 stateAfterStart = graph.add(new FrameState(BytecodeFrame.BEFORE_BCI)); 846 } else { 847 ResolvedJavaMethod original = intrinsicContext.getOriginalMethod(); 848 ValueNode[] locals; 849 if (original.getMaxLocals() == frameState.localsSize() || original.isNative()) { 850 locals = new ValueNode[original.getMaxLocals()]; 851 for (int i = 0; i < locals.length; i++) { 852 ValueNode node = frameState.locals[i]; 853 if (node == FrameState.TWO_SLOT_MARKER) { 854 node = null; 855 } 856 locals[i] = node; 857 } 858 } else { 859 locals = new ValueNode[original.getMaxLocals()]; 860 int parameterCount = original.getSignature().getParameterCount(!original.isStatic()); 861 for (int i = 0; i < parameterCount; i++) { 862 ValueNode param = frameState.locals[i]; 863 if (param == FrameState.TWO_SLOT_MARKER) { 864 param = null; 865 } 866 locals[i] = param; 867 assert param == null || param instanceof ParameterNode || param.isConstant(); 868 } 869 } 870 ValueNode[] stack = {}; 871 int stackSize = 0; 872 ValueNode[] locks = {}; 873 List<MonitorIdNode> monitorIds = Collections.emptyList(); 874 stateAfterStart = graph.add(new FrameState(null, new ResolvedJavaMethodBytecode(original), 0, locals, stack, stackSize, locks, monitorIds, false, false)); 875 } 876 return stateAfterStart; 877 } 878 879 /** 880 * @param type the unresolved type of the constant 881 */ 882 protected void handleUnresolvedLoadConstant(JavaType type) { 883 assert !graphBuilderConfig.eagerResolving(); 884 append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); 885 } 886 887 /** 888 * @param type the unresolved type of the type check 889 * @param object the object value whose type is being checked against {@code type} 890 */ 891 protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) { 892 assert !graphBuilderConfig.eagerResolving(); 893 append(new FixedGuardNode(graph.unique(IsNullNode.create(object)), Unresolved, InvalidateRecompile)); 894 frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER)); 895 } 896 897 /** 898 * @param type the unresolved type of the type check 899 * @param object the object value whose type is being checked against {@code type} 900 */ 901 protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) { 902 assert !graphBuilderConfig.eagerResolving(); 903 AbstractBeginNode successor = graph.add(new BeginNode()); 904 DeoptimizeNode deopt = graph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)); 905 append(new IfNode(graph.unique(IsNullNode.create(object)), successor, deopt, 1)); 906 lastInstr = successor; 907 frameState.push(JavaKind.Int, appendConstant(JavaConstant.INT_0)); 908 } 909 910 /** 911 * @param type the type being instantiated 912 */ 913 protected void handleUnresolvedNewInstance(JavaType type) { 914 assert !graphBuilderConfig.eagerResolving(); 915 append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); 916 } 917 918 /** 919 * @param type the type of the array being instantiated 920 * @param length the length of the array 921 */ 922 protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) { 923 assert !graphBuilderConfig.eagerResolving(); 924 append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); 925 } 926 927 /** 928 * @param type the type being instantiated 929 * @param dims the dimensions for the multi-array 930 */ 931 protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) { 932 assert !graphBuilderConfig.eagerResolving(); 933 append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); 934 } 935 936 /** 937 * @param field the unresolved field 938 * @param receiver the object containing the field or {@code null} if {@code field} is static 939 */ 940 protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) { 941 assert !graphBuilderConfig.eagerResolving(); 942 append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); 943 } 944 945 /** 946 * @param field the unresolved field 947 * @param value the value being stored to the field 948 * @param receiver the object containing the field or {@code null} if {@code field} is static 949 */ 950 protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) { 951 assert !graphBuilderConfig.eagerResolving(); 952 append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); 953 } 954 955 /** 956 * @param type 957 */ 958 protected void handleUnresolvedExceptionType(JavaType type) { 959 assert !graphBuilderConfig.eagerResolving(); 960 append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); 961 } 962 963 /** 964 * @param javaMethod 965 * @param invokeKind 966 */ 967 protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) { 968 assert !graphBuilderConfig.eagerResolving(); 969 append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); 970 } 971 972 private AbstractBeginNode handleException(ValueNode exceptionObject, int bci) { 973 assert bci == BytecodeFrame.BEFORE_BCI || bci == bci() : "invalid bci"; 974 Debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, (profilingInfo == null ? "" : profilingInfo.getExceptionSeen(bci))); 975 976 FrameStateBuilder dispatchState = frameState.copy(); 977 dispatchState.clearStack(); 978 979 AbstractBeginNode dispatchBegin; 980 if (exceptionObject == null) { 981 ExceptionObjectNode newExceptionObject = graph.add(new ExceptionObjectNode(metaAccess)); 982 dispatchBegin = newExceptionObject; 983 dispatchState.push(JavaKind.Object, dispatchBegin); 984 dispatchState.setRethrowException(true); 985 newExceptionObject.setStateAfter(dispatchState.create(bci, newExceptionObject)); 986 } else { 987 dispatchBegin = graph.add(new BeginNode()); 988 dispatchState.push(JavaKind.Object, exceptionObject); 989 dispatchState.setRethrowException(true); 990 } 991 this.controlFlowSplit = true; 992 FixedWithNextNode finishedDispatch = finishInstruction(dispatchBegin, dispatchState); 993 994 createHandleExceptionTarget(finishedDispatch, bci, dispatchState); 995 996 return dispatchBegin; 997 } 998 999 protected void createHandleExceptionTarget(FixedWithNextNode finishedDispatch, int bci, FrameStateBuilder dispatchState) { 1000 BciBlock dispatchBlock = currentBlock.exceptionDispatchBlock(); 1001 /* 1002 * The exception dispatch block is always for the last bytecode of a block, so if we are not 1003 * at the endBci yet, there is no exception handler for this bci and we can unwind 1004 * immediately. 1005 */ 1006 if (bci != currentBlock.endBci || dispatchBlock == null) { 1007 dispatchBlock = blockMap.getUnwindBlock(); 1008 } 1009 1010 FixedNode target = createTarget(dispatchBlock, dispatchState); 1011 finishedDispatch.setNext(target); 1012 } 1013 1014 protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, JavaKind kind) { 1015 return LoadIndexedNode.create(graph.getAssumptions(), array, index, kind, metaAccess, constantReflection); 1016 } 1017 1018 protected void genStoreIndexed(ValueNode array, ValueNode index, JavaKind kind, ValueNode value) { 1019 add(new StoreIndexedNode(array, index, kind, value)); 1020 } 1021 1022 protected ValueNode genIntegerAdd(ValueNode x, ValueNode y) { 1023 return AddNode.create(x, y); 1024 } 1025 1026 protected ValueNode genIntegerSub(ValueNode x, ValueNode y) { 1027 return SubNode.create(x, y); 1028 } 1029 1030 protected ValueNode genIntegerMul(ValueNode x, ValueNode y) { 1031 return MulNode.create(x, y); 1032 } 1033 1034 protected ValueNode genFloatAdd(ValueNode x, ValueNode y) { 1035 return AddNode.create(x, y); 1036 } 1037 1038 protected ValueNode genFloatSub(ValueNode x, ValueNode y) { 1039 return SubNode.create(x, y); 1040 } 1041 1042 protected ValueNode genFloatMul(ValueNode x, ValueNode y) { 1043 return MulNode.create(x, y); 1044 } 1045 1046 protected ValueNode genFloatDiv(ValueNode x, ValueNode y) { 1047 return DivNode.create(x, y); 1048 } 1049 1050 protected ValueNode genFloatRem(ValueNode x, ValueNode y) { 1051 return new RemNode(x, y); 1052 } 1053 1054 protected ValueNode genIntegerDiv(ValueNode x, ValueNode y) { 1055 return new SignedDivNode(x, y); 1056 } 1057 1058 protected ValueNode genIntegerRem(ValueNode x, ValueNode y) { 1059 return new SignedRemNode(x, y); 1060 } 1061 1062 protected ValueNode genNegateOp(ValueNode x) { 1063 return (new NegateNode(x)); 1064 } 1065 1066 protected ValueNode genLeftShift(ValueNode x, ValueNode y) { 1067 return new LeftShiftNode(x, y); 1068 } 1069 1070 protected ValueNode genRightShift(ValueNode x, ValueNode y) { 1071 return new RightShiftNode(x, y); 1072 } 1073 1074 protected ValueNode genUnsignedRightShift(ValueNode x, ValueNode y) { 1075 return new UnsignedRightShiftNode(x, y); 1076 } 1077 1078 protected ValueNode genAnd(ValueNode x, ValueNode y) { 1079 return AndNode.create(x, y); 1080 } 1081 1082 protected ValueNode genOr(ValueNode x, ValueNode y) { 1083 return OrNode.create(x, y); 1084 } 1085 1086 protected ValueNode genXor(ValueNode x, ValueNode y) { 1087 return XorNode.create(x, y); 1088 } 1089 1090 protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) { 1091 return NormalizeCompareNode.create(x, y, isUnorderedLess, constantReflection); 1092 } 1093 1094 protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) { 1095 return FloatConvertNode.create(op, input); 1096 } 1097 1098 protected ValueNode genNarrow(ValueNode input, int bitCount) { 1099 return NarrowNode.create(input, bitCount); 1100 } 1101 1102 protected ValueNode genSignExtend(ValueNode input, int bitCount) { 1103 return SignExtendNode.create(input, bitCount); 1104 } 1105 1106 protected ValueNode genZeroExtend(ValueNode input, int bitCount) { 1107 return ZeroExtendNode.create(input, bitCount); 1108 } 1109 1110 protected void genGoto() { 1111 ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin(); 1112 if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { 1113 FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); 1114 int targetBci = currentBlock.getSuccessor(0).startBci; 1115 profilingPlugin.profileGoto(this, method, bci(), targetBci, stateBefore); 1116 } 1117 appendGoto(currentBlock.getSuccessor(0)); 1118 assert currentBlock.numNormalSuccessors() == 1; 1119 } 1120 1121 protected LogicNode genObjectEquals(ValueNode x, ValueNode y) { 1122 return ObjectEqualsNode.create(x, y, constantReflection); 1123 } 1124 1125 protected LogicNode genIntegerEquals(ValueNode x, ValueNode y) { 1126 return IntegerEqualsNode.create(x, y, constantReflection); 1127 } 1128 1129 protected LogicNode genIntegerLessThan(ValueNode x, ValueNode y) { 1130 return IntegerLessThanNode.create(x, y, constantReflection); 1131 } 1132 1133 protected ValueNode genUnique(ValueNode x) { 1134 return graph.addOrUniqueWithInputs(x); 1135 } 1136 1137 protected LogicNode genUnique(LogicNode x) { 1138 return graph.addOrUniqueWithInputs(x); 1139 } 1140 1141 protected ValueNode genIfNode(LogicNode condition, FixedNode falseSuccessor, FixedNode trueSuccessor, double d) { 1142 return new IfNode(condition, falseSuccessor, trueSuccessor, d); 1143 } 1144 1145 protected void genThrow() { 1146 genInfoPointNode(InfopointReason.BYTECODE_POSITION, null); 1147 1148 ValueNode exception = frameState.pop(JavaKind.Object); 1149 FixedGuardNode nullCheck = append(new FixedGuardNode(graph.unique(IsNullNode.create(exception)), NullCheckException, InvalidateReprofile, true)); 1150 PiNode nonNullException = graph.unique(new PiNode(exception, exception.stamp().join(objectNonNull()), nullCheck)); 1151 lastInstr.setNext(handleException(nonNullException, bci())); 1152 } 1153 1154 protected LogicNode createInstanceOf(TypeReference type, ValueNode object) { 1155 return InstanceOfNode.create(type, object); 1156 } 1157 1158 protected AnchoringNode createAnchor(JavaTypeProfile profile) { 1159 if (profile == null || profile.getNotRecordedProbability() > 0.0) { 1160 return null; 1161 } else { 1162 return append(new ValueAnchorNode(null)); 1163 } 1164 } 1165 1166 protected LogicNode createInstanceOf(TypeReference type, ValueNode object, JavaTypeProfile profile) { 1167 return InstanceOfNode.create(type, object, profile, createAnchor(profile)); 1168 } 1169 1170 protected LogicNode createInstanceOfAllowNull(TypeReference type, ValueNode object, JavaTypeProfile profile) { 1171 return InstanceOfNode.createAllowNull(type, object, profile, createAnchor(profile)); 1172 } 1173 1174 protected ValueNode genConditional(ValueNode x) { 1175 return new ConditionalNode((LogicNode) x); 1176 } 1177 1178 protected NewInstanceNode createNewInstance(ResolvedJavaType type, boolean fillContents) { 1179 return new NewInstanceNode(type, fillContents); 1180 } 1181 1182 protected NewArrayNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents) { 1183 return new NewArrayNode(elementType, length, fillContents); 1184 } 1185 1186 protected NewMultiArrayNode createNewMultiArray(ResolvedJavaType type, ValueNode[] dimensions) { 1187 return new NewMultiArrayNode(type, dimensions); 1188 } 1189 1190 protected ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field) { 1191 StampPair stamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, field.getType(), false); 1192 if (stamp == null) { 1193 return LoadFieldNode.create(this.graph.getAssumptions(), receiver, field); 1194 } else { 1195 return LoadFieldNode.createOverrideStamp(stamp, receiver, field); 1196 } 1197 } 1198 1199 protected ValueNode emitExplicitNullCheck(ValueNode receiver) { 1200 if (StampTool.isPointerNonNull(receiver.stamp())) { 1201 return receiver; 1202 } 1203 BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, NullPointerException.class)); 1204 AbstractBeginNode falseSucc = graph.add(new BeginNode()); 1205 PiNode nonNullReceiver = graph.unique(new PiNode(receiver, objectNonNull(), falseSucc)); 1206 append(new IfNode(graph.unique(IsNullNode.create(receiver)), exception, falseSucc, 0.01)); 1207 lastInstr = falseSucc; 1208 1209 exception.setStateAfter(createFrameState(bci(), exception)); 1210 exception.setNext(handleException(exception, bci())); 1211 EXPLICIT_EXCEPTIONS.increment(); 1212 return nonNullReceiver; 1213 } 1214 1215 protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) { 1216 AbstractBeginNode trueSucc = graph.add(new BeginNode()); 1217 BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index)); 1218 append(new IfNode(graph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99)); 1219 lastInstr = trueSucc; 1220 1221 exception.setStateAfter(createFrameState(bci(), exception)); 1222 exception.setNext(handleException(exception, bci())); 1223 } 1224 1225 protected ValueNode genArrayLength(ValueNode x) { 1226 return ArrayLengthNode.create(x, constantReflection); 1227 } 1228 1229 protected void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) { 1230 StoreFieldNode storeFieldNode = new StoreFieldNode(receiver, field, value); 1231 append(storeFieldNode); 1232 storeFieldNode.setStateAfter(this.createFrameState(stream.nextBCI(), storeFieldNode)); 1233 } 1234 1235 /** 1236 * Ensure that concrete classes are at least linked before generating an invoke. Interfaces may 1237 * never be linked so simply return true for them. 1238 * 1239 * @param target 1240 * @return true if the declared holder is an interface or is linked 1241 */ 1242 private static boolean callTargetIsResolved(JavaMethod target) { 1243 if (target instanceof ResolvedJavaMethod) { 1244 ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; 1245 ResolvedJavaType resolvedType = resolvedTarget.getDeclaringClass(); 1246 return resolvedType.isInterface() || resolvedType.isLinked(); 1247 } 1248 return false; 1249 } 1250 1251 protected void genInvokeStatic(JavaMethod target) { 1252 if (callTargetIsResolved(target)) { 1253 ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; 1254 ResolvedJavaType holder = resolvedTarget.getDeclaringClass(); 1255 if (!holder.isInitialized() && ResolveClassBeforeStaticInvoke.getValue(options)) { 1256 handleUnresolvedInvoke(target, InvokeKind.Static); 1257 } else { 1258 ValueNode classInit = null; 1259 ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin(); 1260 if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedTarget.getDeclaringClass())) { 1261 FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); 1262 classInit = classInitializationPlugin.apply(this, resolvedTarget.getDeclaringClass(), stateBefore); 1263 } 1264 1265 ValueNode[] args = frameState.popArguments(resolvedTarget.getSignature().getParameterCount(false)); 1266 Invoke invoke = appendInvoke(InvokeKind.Static, resolvedTarget, args); 1267 if (invoke != null) { 1268 invoke.setClassInit(classInit); 1269 } 1270 } 1271 } else { 1272 handleUnresolvedInvoke(target, InvokeKind.Static); 1273 } 1274 } 1275 1276 protected void genInvokeInterface(JavaMethod target) { 1277 if (callTargetIsResolved(target)) { 1278 ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); 1279 appendInvoke(InvokeKind.Interface, (ResolvedJavaMethod) target, args); 1280 } else { 1281 handleUnresolvedInvoke(target, InvokeKind.Interface); 1282 } 1283 } 1284 1285 protected void genInvokeDynamic(JavaMethod target) { 1286 if (target instanceof ResolvedJavaMethod) { 1287 JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC); 1288 if (appendix != null) { 1289 frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph)); 1290 } 1291 ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(false)); 1292 appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); 1293 } else { 1294 handleUnresolvedInvoke(target, InvokeKind.Static); 1295 } 1296 } 1297 1298 protected void genInvokeVirtual(JavaMethod target) { 1299 if (callTargetIsResolved(target)) { 1300 /* 1301 * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) 1302 * or MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see 1303 * https://wikis.oracle.com/display/HotSpotInternals/Method+handles +and+invokedynamic 1304 */ 1305 boolean hasReceiver = !((ResolvedJavaMethod) target).isStatic(); 1306 JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI(), Bytecodes.INVOKEVIRTUAL); 1307 if (appendix != null) { 1308 frameState.push(JavaKind.Object, ConstantNode.forConstant(appendix, metaAccess, graph)); 1309 } 1310 ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver)); 1311 if (hasReceiver) { 1312 appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); 1313 } else { 1314 appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); 1315 } 1316 } else { 1317 handleUnresolvedInvoke(target, InvokeKind.Virtual); 1318 } 1319 1320 } 1321 1322 protected void genInvokeSpecial(JavaMethod target) { 1323 if (callTargetIsResolved(target)) { 1324 assert target != null; 1325 assert target.getSignature() != null; 1326 ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); 1327 appendInvoke(InvokeKind.Special, (ResolvedJavaMethod) target, args); 1328 } else { 1329 handleUnresolvedInvoke(target, InvokeKind.Special); 1330 } 1331 } 1332 1333 private InvokeKind currentInvokeKind; 1334 private JavaType currentInvokeReturnType; 1335 protected FrameStateBuilder frameState; 1336 protected BciBlock currentBlock; 1337 protected final BytecodeStream stream; 1338 protected final GraphBuilderConfiguration graphBuilderConfig; 1339 protected final ResolvedJavaMethod method; 1340 protected final Bytecode code; 1341 protected final BytecodeProvider bytecodeProvider; 1342 protected final ProfilingInfo profilingInfo; 1343 protected final OptimisticOptimizations optimisticOpts; 1344 protected final ConstantPool constantPool; 1345 protected final MetaAccessProvider metaAccess; 1346 private final ConstantReflectionProvider constantReflection; 1347 private final ConstantFieldProvider constantFieldProvider; 1348 private final StampProvider stampProvider; 1349 protected final IntrinsicContext intrinsicContext; 1350 1351 @Override 1352 public InvokeKind getInvokeKind() { 1353 return currentInvokeKind; 1354 } 1355 1356 @Override 1357 public JavaType getInvokeReturnType() { 1358 return currentInvokeReturnType; 1359 } 1360 1361 private boolean forceInliningEverything; 1362 1363 @Override 1364 public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean inlineEverything) { 1365 boolean previous = forceInliningEverything; 1366 forceInliningEverything = previous || inlineEverything; 1367 try { 1368 appendInvoke(invokeKind, targetMethod, args); 1369 } finally { 1370 forceInliningEverything = previous; 1371 } 1372 } 1373 1374 @Override 1375 public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType) { 1376 createNonInlinedInvoke(callTarget, resultType, null); 1377 } 1378 1379 private Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) { 1380 ResolvedJavaMethod targetMethod = initialTargetMethod; 1381 InvokeKind invokeKind = initialInvokeKind; 1382 if (initialInvokeKind.isIndirect()) { 1383 ResolvedJavaType contextType = this.frameState.getMethod().getDeclaringClass(); 1384 ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(initialInvokeKind, args[0], initialTargetMethod, contextType); 1385 if (specialCallTarget != null) { 1386 invokeKind = InvokeKind.Special; 1387 targetMethod = specialCallTarget; 1388 } 1389 } 1390 1391 JavaKind resultType = targetMethod.getSignature().getReturnKind(); 1392 if (!parsingIntrinsic() && DeoptALot.getValue(options)) { 1393 append(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint)); 1394 frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, graph)); 1395 return null; 1396 } 1397 1398 JavaType returnType = targetMethod.getSignature().getReturnType(method.getDeclaringClass()); 1399 if (graphBuilderConfig.eagerResolving() || parsingIntrinsic()) { 1400 returnType = returnType.resolve(targetMethod.getDeclaringClass()); 1401 } 1402 if (invokeKind.hasReceiver()) { 1403 args[0] = emitExplicitExceptions(args[0]); 1404 1405 if (args[0].isNullConstant()) { 1406 append(new DeoptimizeNode(InvalidateRecompile, NullCheckException)); 1407 return null; 1408 } 1409 } 1410 1411 InlineInfo inlineInfo = null; 1412 try { 1413 currentInvokeReturnType = returnType; 1414 currentInvokeKind = invokeKind; 1415 if (tryNodePluginForInvocation(args, targetMethod)) { 1416 if (TraceParserPlugins.getValue(options)) { 1417 traceWithContext("used node plugin for %s", targetMethod.format("%h.%n(%p)")); 1418 } 1419 return null; 1420 } 1421 1422 if (!invokeKind.isIndirect() || (UseGuardedIntrinsics.getValue(options) && !GeneratePIC.getValue(options))) { 1423 if (tryInvocationPlugin(invokeKind, args, targetMethod, resultType, returnType)) { 1424 if (TraceParserPlugins.getValue(options)) { 1425 traceWithContext("used invocation plugin for %s", targetMethod.format("%h.%n(%p)")); 1426 } 1427 return null; 1428 } 1429 } 1430 if (invokeKind.isDirect()) { 1431 1432 inlineInfo = tryInline(args, targetMethod); 1433 if (inlineInfo == SUCCESSFULLY_INLINED) { 1434 return null; 1435 } 1436 } 1437 } finally { 1438 currentInvokeReturnType = null; 1439 currentInvokeKind = null; 1440 } 1441 1442 JavaTypeProfile profile = null; 1443 if (invokeKind.isIndirect() && profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) { 1444 profile = profilingInfo.getTypeProfile(bci()); 1445 } 1446 return createNonInlinedInvoke(args, targetMethod, invokeKind, resultType, returnType, inlineInfo, profile); 1447 } 1448 1449 protected Invoke createNonInlinedInvoke(ValueNode[] args, ResolvedJavaMethod targetMethod, InvokeKind invokeKind, 1450 JavaKind resultType, JavaType returnType, InlineInfo inlineInfo, JavaTypeProfile profile) { 1451 1452 StampPair returnStamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, returnType, false); 1453 if (returnStamp == null) { 1454 returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false); 1455 } 1456 1457 MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, args, returnStamp, profile)); 1458 Invoke invoke = createNonInlinedInvoke(callTarget, resultType, inlineInfo); 1459 1460 for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) { 1461 plugin.notifyNotInlined(this, targetMethod, invoke); 1462 } 1463 1464 return invoke; 1465 } 1466 1467 protected Invoke createNonInlinedInvoke(CallTargetNode callTarget, JavaKind resultType, InlineInfo inlineInfo) { 1468 if (omitInvokeExceptionEdge(callTarget, inlineInfo)) { 1469 return createInvoke(callTarget, resultType); 1470 } else { 1471 Invoke invoke = createInvokeWithException(callTarget, resultType); 1472 AbstractBeginNode beginNode = graph.add(KillingBeginNode.create(LocationIdentity.any())); 1473 invoke.setNext(beginNode); 1474 lastInstr = beginNode; 1475 return invoke; 1476 } 1477 } 1478 1479 /** 1480 * If the method returns true, the invocation of the given {@link MethodCallTargetNode call 1481 * target} does not need an exception edge. 1482 * 1483 * @param callTarget The call target. 1484 */ 1485 protected boolean omitInvokeExceptionEdge(CallTargetNode callTarget, InlineInfo lastInlineInfo) { 1486 if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION) { 1487 return false; 1488 } else if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_NO_EXCEPTION) { 1489 return true; 1490 } else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.CheckAll) { 1491 return false; 1492 } else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.ExplicitOnly) { 1493 return false; 1494 } else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.OmitAll) { 1495 return true; 1496 } else { 1497 assert graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.Profile; 1498 // be conservative if information was not recorded (could result in endless 1499 // recompiles otherwise) 1500 return (!StressInvokeWithExceptionNode.getValue(options) && optimisticOpts.useExceptionProbability(getOptions()) && profilingInfo != null && 1501 profilingInfo.getExceptionSeen(bci()) == TriState.FALSE); 1502 } 1503 } 1504 1505 /** 1506 * Contains all the assertion checking logic around the application of an 1507 * {@link InvocationPlugin}. This class is only loaded when assertions are enabled. 1508 */ 1509 class InvocationPluginAssertions { 1510 final InvocationPlugin plugin; 1511 final ValueNode[] args; 1512 final ResolvedJavaMethod targetMethod; 1513 final JavaKind resultType; 1514 final int beforeStackSize; 1515 final boolean needsNullCheck; 1516 final int nodeCount; 1517 final Mark mark; 1518 1519 InvocationPluginAssertions(InvocationPlugin plugin, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) { 1520 guarantee(Assertions.ENABLED, "%s should only be loaded and instantiated if assertions are enabled", getClass().getSimpleName()); 1521 this.plugin = plugin; 1522 this.targetMethod = targetMethod; 1523 this.args = args; 1524 this.resultType = resultType; 1525 this.beforeStackSize = frameState.stackSize(); 1526 this.needsNullCheck = !targetMethod.isStatic() && args[0].getStackKind() == JavaKind.Object && !StampTool.isPointerNonNull(args[0].stamp()); 1527 this.nodeCount = graph.getNodeCount(); 1528 this.mark = graph.getMark(); 1529 } 1530 1531 String error(String format, Object... a) { 1532 return String.format(format, a) + String.format("%n\tplugin at %s", plugin.getApplySourceLocation(metaAccess)); 1533 } 1534 1535 boolean check(boolean pluginResult) { 1536 if (pluginResult == true) { 1537 int expectedStackSize = beforeStackSize + resultType.getSlotCount(); 1538 assert expectedStackSize == frameState.stackSize() : error("plugin manipulated the stack incorrectly: expected=%d, actual=%d", expectedStackSize, frameState.stackSize()); 1539 NodeIterable<Node> newNodes = graph.getNewNodes(mark); 1540 assert !needsNullCheck || isPointerNonNull(args[0].stamp()) : error("plugin needs to null check the receiver of %s: receiver=%s", targetMethod.format("%H.%n(%p)"), args[0]); 1541 for (Node n : newNodes) { 1542 if (n instanceof StateSplit) { 1543 StateSplit stateSplit = (StateSplit) n; 1544 assert stateSplit.stateAfter() != null || !stateSplit.hasSideEffect() : error("%s node added by plugin for %s need to have a non-null frame state: %s", 1545 StateSplit.class.getSimpleName(), targetMethod.format("%H.%n(%p)"), stateSplit); 1546 } 1547 } 1548 try { 1549 graphBuilderConfig.getPlugins().getInvocationPlugins().checkNewNodes(BytecodeParser.this, plugin, newNodes); 1550 } catch (Throwable t) { 1551 throw new AssertionError(error("Error in plugin"), t); 1552 } 1553 } else { 1554 assert nodeCount == graph.getNodeCount() : error("plugin that returns false must not create new nodes"); 1555 assert beforeStackSize == frameState.stackSize() : error("plugin that returns false must not modify the stack"); 1556 } 1557 return true; 1558 } 1559 } 1560 1561 protected static class IntrinsicGuard { 1562 final FixedWithNextNode lastInstr; 1563 final Mark mark; 1564 final AbstractBeginNode nonIntrinsicBranch; 1565 final ValueNode receiver; 1566 final JavaTypeProfile profile; 1567 1568 public IntrinsicGuard(FixedWithNextNode lastInstr, ValueNode receiver, Mark mark, AbstractBeginNode nonIntrinsicBranch, JavaTypeProfile profile) { 1569 this.lastInstr = lastInstr; 1570 this.receiver = receiver; 1571 this.mark = mark; 1572 this.nonIntrinsicBranch = nonIntrinsicBranch; 1573 this.profile = profile; 1574 } 1575 } 1576 1577 /** 1578 * Weaves a test of the receiver type to ensure the dispatch will select {@code targetMethod} 1579 * and not another method that overrides it. This should only be called if there is an intrinsic 1580 * (i.e., an {@link InvocationPlugin}) for {@code targetMethod} and the invocation is indirect. 1581 * 1582 * The control flow woven around the intrinsic is as follows: 1583 * 1584 * <pre> 1585 * if (LoadMethod(LoadHub(receiver)) == targetMethod) { 1586 * <intrinsic for targetMethod> 1587 * } else { 1588 * <virtual call to targetMethod> 1589 * } 1590 * </pre> 1591 * 1592 * The {@code else} branch is woven by {@link #afterInvocationPluginExecution}. 1593 * 1594 * @return {@code null} if the intrinsic cannot be used otherwise an object to be used by 1595 * {@link #afterInvocationPluginExecution} to weave code for the non-intrinsic branch 1596 */ 1597 protected IntrinsicGuard guardIntrinsic(ValueNode[] args, ResolvedJavaMethod targetMethod, InvocationPluginReceiver pluginReceiver) { 1598 ValueNode intrinsicReceiver = args[0]; 1599 ResolvedJavaType receiverType = StampTool.typeOrNull(intrinsicReceiver); 1600 if (receiverType == null) { 1601 // The verifier guarantees it to be at least type declaring targetMethod 1602 receiverType = targetMethod.getDeclaringClass(); 1603 } 1604 ResolvedJavaMethod resolvedMethod = receiverType.resolveMethod(targetMethod, method.getDeclaringClass()); 1605 if (resolvedMethod == null || resolvedMethod.equals(targetMethod)) { 1606 assert resolvedMethod == null || targetMethod.getDeclaringClass().isAssignableFrom(resolvedMethod.getDeclaringClass()); 1607 Mark mark = graph.getMark(); 1608 FixedWithNextNode currentLastInstr = lastInstr; 1609 ValueNode nonNullReceiver = pluginReceiver.get(); 1610 Stamp methodStamp = stampProvider.createMethodStamp(); 1611 LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, nonNullReceiver)); 1612 LoadMethodNode actual = append(new LoadMethodNode(methodStamp, targetMethod, receiverType, method.getDeclaringClass(), hub)); 1613 ConstantNode expected = graph.unique(ConstantNode.forConstant(methodStamp, targetMethod.getEncoding(), getMetaAccess())); 1614 LogicNode compare = graph.unique(CompareNode.createCompareNode(Condition.EQ, actual, expected, constantReflection)); 1615 1616 JavaTypeProfile profile = null; 1617 if (profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) { 1618 profile = profilingInfo.getTypeProfile(bci()); 1619 if (profile != null) { 1620 JavaTypeProfile newProfile = adjustProfileForInvocationPlugin(profile, targetMethod); 1621 if (newProfile != profile) { 1622 if (newProfile.getTypes().length == 0) { 1623 // All profiled types select the intrinsic so 1624 // emit a fixed guard instead of a if-then-else. 1625 lastInstr = append(new FixedGuardNode(compare, TypeCheckedInliningViolated, InvalidateReprofile, false)); 1626 return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, null, null); 1627 } 1628 } else { 1629 // No profiled types select the intrinsic so emit a virtual call 1630 return null; 1631 } 1632 profile = newProfile; 1633 } 1634 } 1635 1636 AbstractBeginNode intrinsicBranch = graph.add(new BeginNode()); 1637 AbstractBeginNode nonIntrinsicBranch = graph.add(new BeginNode()); 1638 append(new IfNode(compare, intrinsicBranch, nonIntrinsicBranch, 0.01)); 1639 lastInstr = intrinsicBranch; 1640 return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, nonIntrinsicBranch, profile); 1641 } else { 1642 // Receiver selects an overriding method so emit a virtual call 1643 return null; 1644 } 1645 } 1646 1647 /** 1648 * Adjusts the profile for an indirect invocation of a virtual method for which there is an 1649 * intrinsic. The adjustment made by this method is to remove all types from the profile that do 1650 * not override {@code targetMethod}. 1651 * 1652 * @param profile the profile to adjust 1653 * @param targetMethod the virtual method for which there is an intrinsic 1654 * @return the adjusted profile or the original {@code profile} object if no adjustment was made 1655 */ 1656 protected JavaTypeProfile adjustProfileForInvocationPlugin(JavaTypeProfile profile, ResolvedJavaMethod targetMethod) { 1657 if (profile.getTypes().length > 0) { 1658 List<ProfiledType> retained = new ArrayList<>(); 1659 double notRecordedProbability = profile.getNotRecordedProbability(); 1660 for (ProfiledType ptype : profile.getTypes()) { 1661 if (!ptype.getType().resolveMethod(targetMethod, method.getDeclaringClass()).equals(targetMethod)) { 1662 retained.add(ptype); 1663 } else { 1664 notRecordedProbability += ptype.getProbability(); 1665 } 1666 } 1667 if (!retained.isEmpty()) { 1668 if (retained.size() != profile.getTypes().length) { 1669 return new JavaTypeProfile(profile.getNullSeen(), notRecordedProbability, retained.toArray(new ProfiledType[retained.size()])); 1670 } 1671 } else { 1672 return new JavaTypeProfile(profile.getNullSeen(), notRecordedProbability, new ProfiledType[0]); 1673 } 1674 } 1675 return profile; 1676 } 1677 1678 /** 1679 * Performs any action required after execution of an invocation plugin. This includes 1680 * {@linkplain InvocationPluginAssertions#check(boolean) checking} invocation plugin invariants 1681 * as well as weaving the {@code else} branch of the code woven by {@link #guardIntrinsic} if 1682 * {@code guard != null}. 1683 */ 1684 protected void afterInvocationPluginExecution(boolean pluginResult, InvocationPluginAssertions assertions, IntrinsicGuard intrinsicGuard, 1685 InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) { 1686 assert assertions.check(pluginResult); 1687 if (intrinsicGuard != null) { 1688 if (pluginResult) { 1689 if (intrinsicGuard.nonIntrinsicBranch != null) { 1690 // Intrinsic emitted: emit a virtual call to the target method and 1691 // merge it with the intrinsic branch 1692 EndNode intrinsicEnd = append(new EndNode()); 1693 1694 FrameStateBuilder intrinsicState = null; 1695 FrameStateBuilder nonIntrinisicState = null; 1696 if (resultType != JavaKind.Void) { 1697 intrinsicState = frameState.copy(); 1698 frameState.pop(resultType); 1699 nonIntrinisicState = frameState; 1700 } 1701 1702 lastInstr = intrinsicGuard.nonIntrinsicBranch; 1703 createNonInlinedInvoke(args, targetMethod, invokeKind, resultType, returnType, null, intrinsicGuard.profile); 1704 1705 EndNode nonIntrinsicEnd = append(new EndNode()); 1706 AbstractMergeNode mergeNode = graph.add(new MergeNode()); 1707 1708 mergeNode.addForwardEnd(intrinsicEnd); 1709 if (intrinsicState != null) { 1710 intrinsicState.merge(mergeNode, nonIntrinisicState); 1711 frameState = intrinsicState; 1712 } 1713 mergeNode.addForwardEnd(nonIntrinsicEnd); 1714 mergeNode.setStateAfter(frameState.create(stream.nextBCI(), mergeNode)); 1715 1716 lastInstr = mergeNode; 1717 } 1718 } else { 1719 // Intrinsic was not applied: remove intrinsic guard 1720 // and restore the original receiver node in the arguments array 1721 intrinsicGuard.lastInstr.setNext(null); 1722 GraphUtil.removeNewNodes(graph, intrinsicGuard.mark); 1723 lastInstr = intrinsicGuard.lastInstr; 1724 args[0] = intrinsicGuard.receiver; 1725 } 1726 } 1727 } 1728 1729 protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) { 1730 InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod); 1731 if (plugin != null) { 1732 1733 if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) { 1734 // Self recursive intrinsic means the original 1735 // method should be called. 1736 assert !targetMethod.hasBytecodes() : "TODO: when does this happen?"; 1737 return false; 1738 } 1739 1740 InvocationPluginReceiver pluginReceiver = invocationPluginReceiver.init(targetMethod, args); 1741 1742 IntrinsicGuard intrinsicGuard = null; 1743 if (invokeKind.isIndirect()) { 1744 intrinsicGuard = guardIntrinsic(args, targetMethod, pluginReceiver); 1745 if (intrinsicGuard == null) { 1746 return false; 1747 } else if (intrinsicGuard.nonIntrinsicBranch == null) { 1748 assert lastInstr instanceof FixedGuardNode; 1749 } 1750 } 1751 1752 InvocationPluginAssertions assertions = Assertions.ENABLED ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null; 1753 if (plugin.execute(this, targetMethod, pluginReceiver, args)) { 1754 afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType); 1755 return true; 1756 } else { 1757 afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType); 1758 } 1759 } 1760 return false; 1761 } 1762 1763 private boolean tryNodePluginForInvocation(ValueNode[] args, ResolvedJavaMethod targetMethod) { 1764 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 1765 if (plugin.handleInvoke(this, targetMethod, args)) { 1766 return true; 1767 } 1768 } 1769 return false; 1770 } 1771 1772 private static final InlineInfo SUCCESSFULLY_INLINED = InlineInfo.createStandardInlineInfo(null); 1773 1774 /** 1775 * Try to inline a method. If the method was inlined, returns {@link #SUCCESSFULLY_INLINED}. 1776 * Otherwise, it returns the {@link InlineInfo} that lead to the decision to not inline it, or 1777 * {@code null} if there is no {@link InlineInfo} for this method. 1778 */ 1779 private InlineInfo tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod) { 1780 boolean canBeInlined = forceInliningEverything || parsingIntrinsic() || targetMethod.canBeInlined(); 1781 if (!canBeInlined) { 1782 return null; 1783 } 1784 1785 if (forceInliningEverything) { 1786 if (inline(targetMethod, targetMethod, null, args)) { 1787 return SUCCESSFULLY_INLINED; 1788 } else { 1789 return null; 1790 } 1791 } 1792 1793 for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) { 1794 InlineInfo inlineInfo = plugin.shouldInlineInvoke(this, targetMethod, args); 1795 if (inlineInfo != null) { 1796 if (inlineInfo.getMethodToInline() != null) { 1797 if (inline(targetMethod, inlineInfo.getMethodToInline(), inlineInfo.getIntrinsicBytecodeProvider(), args)) { 1798 return SUCCESSFULLY_INLINED; 1799 } 1800 } 1801 /* Do not inline, and do not ask the remaining plugins. */ 1802 return inlineInfo; 1803 } 1804 } 1805 return null; 1806 } 1807 1808 private static final int ACCESSOR_BYTECODE_LENGTH = 5; 1809 1810 /** 1811 * Tries to inline {@code targetMethod} if it is an instance field accessor. This avoids the 1812 * overhead of creating and using a nested {@link BytecodeParser} object. 1813 */ 1814 private boolean tryFastInlineAccessor(ValueNode[] args, ResolvedJavaMethod targetMethod) { 1815 byte[] bytecode = targetMethod.getCode(); 1816 if (bytecode.length == ACCESSOR_BYTECODE_LENGTH && 1817 Bytes.beU1(bytecode, 0) == ALOAD_0 && 1818 Bytes.beU1(bytecode, 1) == GETFIELD) { 1819 int b4 = Bytes.beU1(bytecode, 4); 1820 if (b4 >= IRETURN && b4 <= ARETURN) { 1821 int cpi = Bytes.beU2(bytecode, 2); 1822 JavaField field = targetMethod.getConstantPool().lookupField(cpi, targetMethod, GETFIELD); 1823 if (field instanceof ResolvedJavaField) { 1824 ValueNode receiver = invocationPluginReceiver.init(targetMethod, args).get(); 1825 ResolvedJavaField resolvedField = (ResolvedJavaField) field; 1826 genGetField(resolvedField, receiver); 1827 printInlining(targetMethod, targetMethod, true, "inline accessor method (bytecode parsing)"); 1828 return true; 1829 } 1830 } 1831 } 1832 return false; 1833 } 1834 1835 @Override 1836 public boolean intrinsify(BytecodeProvider intrinsicBytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] args) { 1837 if (receiver != null) { 1838 receiver.get(); 1839 } 1840 boolean res = inline(targetMethod, substitute, intrinsicBytecodeProvider, args); 1841 assert res : "failed to inline " + substitute; 1842 return res; 1843 } 1844 1845 private boolean inline(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, BytecodeProvider intrinsicBytecodeProvider, ValueNode[] args) { 1846 traceInlining(targetMethod, inlinedMethod); 1847 IntrinsicContext intrinsic = this.intrinsicContext; 1848 1849 if (intrinsic == null && !graphBuilderConfig.insertFullInfopoints() && 1850 targetMethod.equals(inlinedMethod) && 1851 (targetMethod.getModifiers() & (STATIC | SYNCHRONIZED)) == 0 && 1852 tryFastInlineAccessor(args, targetMethod)) { 1853 return true; 1854 } 1855 1856 if (intrinsic != null && intrinsic.isCallToOriginal(targetMethod)) { 1857 if (intrinsic.isCompilationRoot()) { 1858 // A root compiled intrinsic needs to deoptimize 1859 // if the slow path is taken. During frame state 1860 // assignment, the deopt node will get its stateBefore 1861 // from the start node of the intrinsic 1862 append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint)); 1863 printInlining(targetMethod, inlinedMethod, true, "compilation root (bytecode parsing)"); 1864 return true; 1865 } else { 1866 // Otherwise inline the original method. Any frame state created 1867 // during the inlining will exclude frame(s) in the 1868 // intrinsic method (see HIRFrameStateBuilder.create(int bci)). 1869 if (intrinsic.getOriginalMethod().isNative()) { 1870 printInlining(targetMethod, inlinedMethod, false, "native method (bytecode parsing)"); 1871 return false; 1872 } 1873 printInlining(targetMethod, inlinedMethod, true, "inline intrinsic (bytecode parsing)"); 1874 parseAndInlineCallee(intrinsic.getOriginalMethod(), args, null); 1875 return true; 1876 } 1877 } else { 1878 boolean isIntrinsic = intrinsicBytecodeProvider != null; 1879 if (intrinsic == null && isIntrinsic) { 1880 assert !inlinedMethod.equals(targetMethod); 1881 intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, intrinsicBytecodeProvider, INLINE_DURING_PARSING); 1882 } 1883 if (inlinedMethod.hasBytecodes()) { 1884 for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) { 1885 plugin.notifyBeforeInline(inlinedMethod); 1886 } 1887 printInlining(targetMethod, inlinedMethod, true, "inline method (bytecode parsing)"); 1888 parseAndInlineCallee(inlinedMethod, args, intrinsic); 1889 for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) { 1890 plugin.notifyAfterInline(inlinedMethod); 1891 } 1892 } else { 1893 printInlining(targetMethod, inlinedMethod, false, "no bytecodes (abstract or native) (bytecode parsing)"); 1894 return false; 1895 } 1896 } 1897 return true; 1898 } 1899 1900 private void traceInlining(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod) { 1901 if (TraceInlineDuringParsing.getValue(options) || TraceParserPlugins.getValue(options)) { 1902 if (targetMethod.equals(inlinedMethod)) { 1903 traceWithContext("inlining call to %s", inlinedMethod.format("%h.%n(%p)")); 1904 } else { 1905 traceWithContext("inlining call to %s as intrinsic for %s", inlinedMethod.format("%h.%n(%p)"), targetMethod.format("%h.%n(%p)")); 1906 } 1907 } 1908 } 1909 1910 private void printInlining(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, boolean success, String msg) { 1911 if (HotSpotPrintInlining.getValue(options)) { 1912 if (targetMethod.equals(inlinedMethod)) { 1913 Util.printInlining(inlinedMethod, bci(), getDepth(), success, "%s", msg); 1914 } else { 1915 Util.printInlining(inlinedMethod, bci(), getDepth(), success, "%s intrinsic for %s", msg, targetMethod.format("%h.%n(%p)")); 1916 } 1917 } 1918 } 1919 1920 /** 1921 * Prints a line to {@link TTY} with a prefix indicating the current parse context. The prefix 1922 * is of the form: 1923 * 1924 * <pre> 1925 * {SPACE * n} {name of method being parsed} "(" {file name} ":" {line number} ")" 1926 * </pre> 1927 * 1928 * where {@code n} is the current inlining depth. 1929 * 1930 * @param format a format string 1931 * @param args arguments to the format string 1932 */ 1933 1934 protected void traceWithContext(String format, Object... args) { 1935 StackTraceElement where = code.asStackTraceElement(bci()); 1936 TTY.println(format("%s%s (%s:%d) %s", nSpaces(getDepth()), method.isConstructor() ? method.format("%h.%n") : method.getName(), where.getFileName(), where.getLineNumber(), 1937 format(format, args))); 1938 } 1939 1940 protected BytecodeParserError asParserError(Throwable e) { 1941 if (e instanceof BytecodeParserError) { 1942 return (BytecodeParserError) e; 1943 } 1944 BytecodeParser bp = this; 1945 BytecodeParserError res = new BytecodeParserError(e); 1946 while (bp != null) { 1947 res.addContext("parsing " + bp.code.asStackTraceElement(bp.bci())); 1948 bp = bp.parent; 1949 } 1950 return res; 1951 } 1952 1953 @SuppressWarnings("try") 1954 protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) { 1955 try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, targetMethod.getSignature().toParameterKinds(!targetMethod.isStatic()), args) : null) { 1956 1957 BytecodeParser parser = graphBuilderInstance.createBytecodeParser(graph, this, targetMethod, INVOCATION_ENTRY_BCI, calleeIntrinsicContext); 1958 FrameStateBuilder startFrameState = new FrameStateBuilder(parser, parser.code, graph); 1959 if (!targetMethod.isStatic()) { 1960 args[0] = nullCheckedValue(args[0]); 1961 } 1962 startFrameState.initializeFromArgumentsArray(args); 1963 parser.build(this.lastInstr, startFrameState); 1964 1965 FixedWithNextNode calleeBeforeReturnNode = parser.getBeforeReturnNode(); 1966 this.lastInstr = calleeBeforeReturnNode; 1967 JavaKind calleeReturnKind = targetMethod.getSignature().getReturnKind(); 1968 if (calleeBeforeReturnNode != null) { 1969 ValueNode calleeReturnValue = parser.getReturnValue(); 1970 if (calleeReturnValue != null) { 1971 frameState.push(calleeReturnKind.getStackKind(), calleeReturnValue); 1972 } 1973 } 1974 1975 FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode(); 1976 if (calleeBeforeUnwindNode != null) { 1977 ValueNode calleeUnwindValue = parser.getUnwindValue(); 1978 assert calleeUnwindValue != null; 1979 calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci())); 1980 } 1981 } 1982 } 1983 1984 public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, JavaTypeProfile profile) { 1985 return new MethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, profile); 1986 } 1987 1988 protected InvokeNode createInvoke(CallTargetNode callTarget, JavaKind resultType) { 1989 InvokeNode invoke = append(new InvokeNode(callTarget, bci())); 1990 frameState.pushReturn(resultType, invoke); 1991 invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); 1992 return invoke; 1993 } 1994 1995 protected InvokeWithExceptionNode createInvokeWithException(CallTargetNode callTarget, JavaKind resultType) { 1996 if (currentBlock != null && stream.nextBCI() > currentBlock.endBci) { 1997 /* 1998 * Clear non-live locals early so that the exception handler entry gets the cleared 1999 * state. 2000 */ 2001 frameState.clearNonLiveLocals(currentBlock, liveness, false); 2002 } 2003 2004 AbstractBeginNode exceptionEdge = handleException(null, bci()); 2005 InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci())); 2006 frameState.pushReturn(resultType, invoke); 2007 invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); 2008 return invoke; 2009 } 2010 2011 protected void genReturn(ValueNode returnVal, JavaKind returnKind) { 2012 if (parsingIntrinsic() && returnVal != null) { 2013 if (returnVal instanceof StateSplit) { 2014 StateSplit stateSplit = (StateSplit) returnVal; 2015 FrameState stateAfter = stateSplit.stateAfter(); 2016 if (stateSplit.hasSideEffect()) { 2017 assert stateSplit != null; 2018 if (stateAfter.bci == BytecodeFrame.AFTER_BCI) { 2019 assert stateAfter.usages().count() == 1; 2020 assert stateAfter.usages().first() == stateSplit; 2021 stateAfter.replaceAtUsages(graph.add(new FrameState(BytecodeFrame.AFTER_BCI, returnVal))); 2022 GraphUtil.killWithUnusedFloatingInputs(stateAfter); 2023 } else { 2024 /* 2025 * This must be the return value from within a partial intrinsification. 2026 */ 2027 assert !BytecodeFrame.isPlaceholderBci(stateAfter.bci); 2028 } 2029 } else { 2030 assert stateAfter == null; 2031 } 2032 } 2033 } 2034 if (parent == null) { 2035 frameState.setRethrowException(false); 2036 frameState.clearStack(); 2037 beforeReturn(returnVal, returnKind); 2038 append(new ReturnNode(returnVal)); 2039 } else { 2040 if (blockMap.getReturnCount() == 1 || !controlFlowSplit) { 2041 // There is only a single return. 2042 beforeReturn(returnVal, returnKind); 2043 this.returnValue = returnVal; 2044 this.beforeReturnNode = this.lastInstr; 2045 this.lastInstr = null; 2046 } else { 2047 frameState.setRethrowException(false); 2048 frameState.clearStack(); 2049 if (returnVal != null) { 2050 frameState.push(returnKind, returnVal); 2051 } 2052 assert blockMap.getReturnCount() > 1; 2053 appendGoto(blockMap.getReturnBlock()); 2054 } 2055 } 2056 } 2057 2058 private void beforeReturn(ValueNode x, JavaKind kind) { 2059 if (graph.method() != null && graph.method().isJavaLangObjectInit()) { 2060 /* 2061 * Get the receiver from the initial state since bytecode rewriting could do arbitrary 2062 * things to the state of the locals. 2063 */ 2064 ValueNode receiver = graph.start().stateAfter().localAt(0); 2065 assert receiver != null && receiver.getStackKind() == JavaKind.Object; 2066 if (RegisterFinalizerNode.mayHaveFinalizer(receiver, graph.getAssumptions())) { 2067 append(new RegisterFinalizerNode(receiver)); 2068 } 2069 } 2070 genInfoPointNode(InfopointReason.METHOD_END, x); 2071 if (finalBarrierRequired) { 2072 assert originalReceiver != null; 2073 /* 2074 * When compiling an OSR with a final field store, don't bother tracking the original 2075 * receiver since the receiver cannot be EA'ed. 2076 */ 2077 append(new FinalFieldBarrierNode(entryBCI == INVOCATION_ENTRY_BCI ? originalReceiver : null)); 2078 } 2079 synchronizedEpilogue(BytecodeFrame.AFTER_BCI, x, kind); 2080 } 2081 2082 protected MonitorEnterNode createMonitorEnterNode(ValueNode x, MonitorIdNode monitorId) { 2083 return new MonitorEnterNode(x, monitorId); 2084 } 2085 2086 protected void genMonitorEnter(ValueNode x, int bci) { 2087 MonitorIdNode monitorId = graph.add(new MonitorIdNode(frameState.lockDepth(true))); 2088 MonitorEnterNode monitorEnter = append(createMonitorEnterNode(x, monitorId)); 2089 frameState.pushLock(x, monitorId); 2090 monitorEnter.setStateAfter(createFrameState(bci, monitorEnter)); 2091 } 2092 2093 protected void genMonitorExit(ValueNode x, ValueNode escapedReturnValue, int bci) { 2094 if (frameState.lockDepth(false) == 0) { 2095 throw bailout("unbalanced monitors: too many exits"); 2096 } 2097 MonitorIdNode monitorId = frameState.peekMonitorId(); 2098 ValueNode lockedObject = frameState.popLock(); 2099 if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) { 2100 throw bailout(String.format("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject))); 2101 } 2102 MonitorExitNode monitorExit = append(new MonitorExitNode(lockedObject, monitorId, escapedReturnValue)); 2103 monitorExit.setStateAfter(createFrameState(bci, monitorExit)); 2104 } 2105 2106 protected void genJsr(int dest) { 2107 BciBlock successor = currentBlock.getJsrSuccessor(); 2108 assert successor.startBci == dest : successor.startBci + " != " + dest + " @" + bci(); 2109 JsrScope scope = currentBlock.getJsrScope(); 2110 int nextBci = getStream().nextBCI(); 2111 if (!successor.getJsrScope().pop().equals(scope)) { 2112 throw new JsrNotSupportedBailout("unstructured control flow (internal limitation)"); 2113 } 2114 if (successor.getJsrScope().nextReturnAddress() != nextBci) { 2115 throw new JsrNotSupportedBailout("unstructured control flow (internal limitation)"); 2116 } 2117 ConstantNode nextBciNode = getJsrConstant(nextBci); 2118 frameState.push(JavaKind.Object, nextBciNode); 2119 appendGoto(successor); 2120 } 2121 2122 protected void genRet(int localIndex) { 2123 BciBlock successor = currentBlock.getRetSuccessor(); 2124 ValueNode local = frameState.loadLocal(localIndex, JavaKind.Object); 2125 JsrScope scope = currentBlock.getJsrScope(); 2126 int retAddress = scope.nextReturnAddress(); 2127 ConstantNode returnBciNode = getJsrConstant(retAddress); 2128 LogicNode guard = IntegerEqualsNode.create(local, returnBciNode, constantReflection); 2129 guard = graph.unique(guard); 2130 append(new FixedGuardNode(guard, JavaSubroutineMismatch, InvalidateReprofile)); 2131 if (!successor.getJsrScope().equals(scope.pop())) { 2132 throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)"); 2133 } 2134 appendGoto(successor); 2135 } 2136 2137 private ConstantNode getJsrConstant(long bci) { 2138 JavaConstant nextBciConstant = new RawConstant(bci); 2139 Stamp nextBciStamp = StampFactory.forConstant(nextBciConstant); 2140 ConstantNode nextBciNode = new ConstantNode(nextBciConstant, nextBciStamp); 2141 return graph.unique(nextBciNode); 2142 } 2143 2144 protected void genIntegerSwitch(ValueNode value, ArrayList<BciBlock> actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors) { 2145 if (value.isConstant()) { 2146 JavaConstant constant = (JavaConstant) value.asConstant(); 2147 int constantValue = constant.asInt(); 2148 for (int i = 0; i < keys.length; ++i) { 2149 if (keys[i] == constantValue) { 2150 appendGoto(actualSuccessors.get(keySuccessors[i])); 2151 return; 2152 } 2153 } 2154 appendGoto(actualSuccessors.get(keySuccessors[keys.length])); 2155 } else { 2156 this.controlFlowSplit = true; 2157 double[] successorProbabilities = successorProbabilites(actualSuccessors.size(), keySuccessors, keyProbabilities); 2158 IntegerSwitchNode switchNode = append(new IntegerSwitchNode(value, actualSuccessors.size(), keys, keyProbabilities, keySuccessors)); 2159 for (int i = 0; i < actualSuccessors.size(); i++) { 2160 switchNode.setBlockSuccessor(i, createBlockTarget(successorProbabilities[i], actualSuccessors.get(i), frameState)); 2161 } 2162 } 2163 } 2164 2165 /** 2166 * Helper function that sums up the probabilities of all keys that lead to a specific successor. 2167 * 2168 * @return an array of size successorCount with the accumulated probability for each successor. 2169 */ 2170 private static double[] successorProbabilites(int successorCount, int[] keySuccessors, double[] keyProbabilities) { 2171 double[] probability = new double[successorCount]; 2172 for (int i = 0; i < keySuccessors.length; i++) { 2173 probability[keySuccessors[i]] += keyProbabilities[i]; 2174 } 2175 return probability; 2176 } 2177 2178 protected ConstantNode appendConstant(JavaConstant constant) { 2179 assert constant != null; 2180 return ConstantNode.forConstant(constant, metaAccess, graph); 2181 } 2182 2183 @Override 2184 public <T extends ValueNode> T append(T v) { 2185 if (v.graph() != null) { 2186 return v; 2187 } 2188 T added = graph.addOrUnique(v); 2189 if (added == v) { 2190 updateLastInstruction(v); 2191 } 2192 return added; 2193 } 2194 2195 @Override 2196 public <T extends ValueNode> T recursiveAppend(T v) { 2197 if (v.graph() != null) { 2198 return v; 2199 } 2200 T added = graph.addOrUniqueWithInputs(v); 2201 if (added == v) { 2202 updateLastInstruction(v); 2203 } 2204 return added; 2205 } 2206 2207 private <T extends ValueNode> void updateLastInstruction(T v) { 2208 if (v instanceof FixedNode) { 2209 FixedNode fixedNode = (FixedNode) v; 2210 lastInstr.setNext(fixedNode); 2211 if (fixedNode instanceof FixedWithNextNode) { 2212 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode; 2213 assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end"; 2214 lastInstr = fixedWithNextNode; 2215 } else { 2216 lastInstr = null; 2217 } 2218 } 2219 } 2220 2221 private Target checkLoopExit(FixedNode target, BciBlock targetBlock, FrameStateBuilder state) { 2222 if (currentBlock != null) { 2223 long exits = currentBlock.loops & ~targetBlock.loops; 2224 if (exits != 0) { 2225 LoopExitNode firstLoopExit = null; 2226 LoopExitNode lastLoopExit = null; 2227 2228 int pos = 0; 2229 ArrayList<BciBlock> exitLoops = new ArrayList<>(Long.bitCount(exits)); 2230 do { 2231 long lMask = 1L << pos; 2232 if ((exits & lMask) != 0) { 2233 exitLoops.add(blockMap.getLoopHeader(pos)); 2234 exits &= ~lMask; 2235 } 2236 pos++; 2237 } while (exits != 0); 2238 2239 Collections.sort(exitLoops, new Comparator<BciBlock>() { 2240 2241 @Override 2242 public int compare(BciBlock o1, BciBlock o2) { 2243 return Long.bitCount(o2.loops) - Long.bitCount(o1.loops); 2244 } 2245 }); 2246 2247 int bci = targetBlock.startBci; 2248 if (targetBlock instanceof ExceptionDispatchBlock) { 2249 bci = ((ExceptionDispatchBlock) targetBlock).deoptBci; 2250 } 2251 FrameStateBuilder newState = state.copy(); 2252 for (BciBlock loop : exitLoops) { 2253 LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(loop); 2254 LoopExitNode loopExit = graph.add(new LoopExitNode(loopBegin)); 2255 if (lastLoopExit != null) { 2256 lastLoopExit.setNext(loopExit); 2257 } 2258 if (firstLoopExit == null) { 2259 firstLoopExit = loopExit; 2260 } 2261 lastLoopExit = loopExit; 2262 Debug.log("Target %s Exits %s, scanning framestates...", targetBlock, loop); 2263 newState.clearNonLiveLocals(targetBlock, liveness, true); 2264 newState.insertLoopProxies(loopExit, getEntryState(loop)); 2265 loopExit.setStateAfter(newState.create(bci, loopExit)); 2266 } 2267 2268 lastLoopExit.setNext(target); 2269 return new Target(firstLoopExit, newState); 2270 } 2271 } 2272 return new Target(target, state); 2273 } 2274 2275 private FrameStateBuilder getEntryState(BciBlock block) { 2276 return entryStateArray[block.id]; 2277 } 2278 2279 private void setEntryState(BciBlock block, FrameStateBuilder entryState) { 2280 this.entryStateArray[block.id] = entryState; 2281 } 2282 2283 private void setFirstInstruction(BciBlock block, FixedWithNextNode firstInstruction) { 2284 this.firstInstructionArray[block.id] = firstInstruction; 2285 } 2286 2287 private FixedWithNextNode getFirstInstruction(BciBlock block) { 2288 return firstInstructionArray[block.id]; 2289 } 2290 2291 private FixedNode createTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) { 2292 assert probability >= 0 && probability <= 1.01 : probability; 2293 if (isNeverExecutedCode(probability)) { 2294 return graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); 2295 } else { 2296 assert block != null; 2297 return createTarget(block, stateAfter); 2298 } 2299 } 2300 2301 private FixedNode createTarget(BciBlock block, FrameStateBuilder state) { 2302 return createTarget(block, state, false, false); 2303 } 2304 2305 private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) { 2306 assert block != null && state != null; 2307 assert !block.isExceptionEntry || state.stackSize() == 1; 2308 2309 if (getFirstInstruction(block) == null) { 2310 /* 2311 * This is the first time we see this block as a branch target. Create and return a 2312 * placeholder that later can be replaced with a MergeNode when we see this block again. 2313 */ 2314 FixedNode targetNode; 2315 if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) { 2316 setFirstInstruction(block, lastInstr); 2317 lastInstr = null; 2318 } else { 2319 setFirstInstruction(block, graph.add(new BeginNode())); 2320 } 2321 targetNode = getFirstInstruction(block); 2322 Target target = checkLoopExit(targetNode, block, state); 2323 FixedNode result = target.fixed; 2324 FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state; 2325 setEntryState(block, currentEntryState); 2326 currentEntryState.clearNonLiveLocals(block, liveness, true); 2327 2328 Debug.log("createTarget %s: first visit, result: %s", block, targetNode); 2329 return result; 2330 } 2331 2332 // We already saw this block before, so we have to merge states. 2333 if (!getEntryState(block).isCompatibleWith(state)) { 2334 throw bailout("stacks do not match; bytecodes would not verify"); 2335 } 2336 2337 if (getFirstInstruction(block) instanceof LoopBeginNode) { 2338 assert (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch"; 2339 /* 2340 * Backward loop edge. We need to create a special LoopEndNode and merge with the loop 2341 * begin node created before. 2342 */ 2343 LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block); 2344 LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin)); 2345 Target target = checkLoopExit(loopEnd, block, state); 2346 FixedNode result = target.fixed; 2347 getEntryState(block).merge(loopBegin, target.state); 2348 2349 Debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result); 2350 return result; 2351 } 2352 assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch"; 2353 assert getFirstInstruction(block).next() == null : "bytecodes already parsed for block"; 2354 2355 if (getFirstInstruction(block) instanceof AbstractBeginNode && !(getFirstInstruction(block) instanceof AbstractMergeNode)) { 2356 /* 2357 * This is the second time we see this block. Create the actual MergeNode and the End 2358 * Node for the already existing edge. 2359 */ 2360 AbstractBeginNode beginNode = (AbstractBeginNode) getFirstInstruction(block); 2361 2362 // The EndNode for the already existing edge. 2363 EndNode end = graph.add(new EndNode()); 2364 // The MergeNode that replaces the placeholder. 2365 AbstractMergeNode mergeNode = graph.add(new MergeNode()); 2366 FixedNode next = beginNode.next(); 2367 2368 if (beginNode.predecessor() instanceof ControlSplitNode) { 2369 beginNode.setNext(end); 2370 } else { 2371 beginNode.replaceAtPredecessor(end); 2372 beginNode.safeDelete(); 2373 } 2374 2375 mergeNode.addForwardEnd(end); 2376 mergeNode.setNext(next); 2377 2378 setFirstInstruction(block, mergeNode); 2379 } 2380 2381 AbstractMergeNode mergeNode = (AbstractMergeNode) getFirstInstruction(block); 2382 2383 // The EndNode for the newly merged edge. 2384 EndNode newEnd = graph.add(new EndNode()); 2385 Target target = checkLoopExit(newEnd, block, state); 2386 FixedNode result = target.fixed; 2387 getEntryState(block).merge(mergeNode, target.state); 2388 mergeNode.addForwardEnd(newEnd); 2389 2390 Debug.log("createTarget %s: merging state, result: %s", block, result); 2391 return result; 2392 } 2393 2394 /** 2395 * Returns a block begin node with the specified state. If the specified probability is 0, the 2396 * block deoptimizes immediately. 2397 */ 2398 private AbstractBeginNode createBlockTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) { 2399 FixedNode target = createTarget(probability, block, stateAfter); 2400 AbstractBeginNode begin = BeginNode.begin(target); 2401 2402 assert !(target instanceof DeoptimizeNode && begin instanceof BeginStateSplitNode && 2403 ((BeginStateSplitNode) begin).stateAfter() != null) : "We are not allowed to set the stateAfter of the begin node," + 2404 " because we have to deoptimize to a bci _before_ the actual if, so that the interpreter can update the profiling information."; 2405 return begin; 2406 } 2407 2408 private ValueNode synchronizedObject(FrameStateBuilder state, ResolvedJavaMethod target) { 2409 if (target.isStatic()) { 2410 return appendConstant(getConstantReflection().asJavaClass(target.getDeclaringClass())); 2411 } else { 2412 return state.loadLocal(0, JavaKind.Object); 2413 } 2414 } 2415 2416 @SuppressWarnings("try") 2417 protected void processBlock(BciBlock block) { 2418 // Ignore blocks that have no predecessors by the time their bytecodes are parsed 2419 FixedWithNextNode firstInstruction = getFirstInstruction(block); 2420 if (firstInstruction == null) { 2421 Debug.log("Ignoring block %s", block); 2422 return; 2423 } 2424 try (Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, firstInstruction, block.isLoopHeader)) { 2425 2426 lastInstr = firstInstruction; 2427 frameState = getEntryState(block); 2428 setCurrentFrameState(frameState); 2429 currentBlock = block; 2430 2431 if (firstInstruction instanceof AbstractMergeNode) { 2432 setMergeStateAfter(block, firstInstruction); 2433 } 2434 2435 if (block == blockMap.getReturnBlock()) { 2436 handleReturnBlock(); 2437 } else if (block == blockMap.getUnwindBlock()) { 2438 handleUnwindBlock((ExceptionDispatchBlock) block); 2439 } else if (block instanceof ExceptionDispatchBlock) { 2440 createExceptionDispatch((ExceptionDispatchBlock) block); 2441 } else { 2442 frameState.setRethrowException(false); 2443 iterateBytecodesForBlock(block); 2444 } 2445 } 2446 } 2447 2448 private void handleUnwindBlock(ExceptionDispatchBlock block) { 2449 if (parent == null) { 2450 finishPrepare(lastInstr, block.deoptBci); 2451 frameState.setRethrowException(false); 2452 createUnwind(); 2453 } else { 2454 ValueNode exception = frameState.pop(JavaKind.Object); 2455 this.unwindValue = exception; 2456 this.beforeUnwindNode = this.lastInstr; 2457 } 2458 } 2459 2460 private void handleReturnBlock() { 2461 JavaKind returnKind = method.getSignature().getReturnKind().getStackKind(); 2462 ValueNode x = returnKind == JavaKind.Void ? null : frameState.pop(returnKind); 2463 assert frameState.stackSize() == 0; 2464 beforeReturn(x, returnKind); 2465 this.returnValue = x; 2466 this.beforeReturnNode = this.lastInstr; 2467 } 2468 2469 private void setMergeStateAfter(BciBlock block, FixedWithNextNode firstInstruction) { 2470 AbstractMergeNode abstractMergeNode = (AbstractMergeNode) firstInstruction; 2471 if (abstractMergeNode.stateAfter() == null) { 2472 int bci = block.startBci; 2473 if (block instanceof ExceptionDispatchBlock) { 2474 bci = ((ExceptionDispatchBlock) block).deoptBci; 2475 } 2476 abstractMergeNode.setStateAfter(createFrameState(bci, abstractMergeNode)); 2477 } 2478 } 2479 2480 private void createUnwind() { 2481 assert frameState.stackSize() == 1 : frameState; 2482 synchronizedEpilogue(BytecodeFrame.AFTER_EXCEPTION_BCI, null, null); 2483 ValueNode exception = frameState.pop(JavaKind.Object); 2484 append(new UnwindNode(exception)); 2485 } 2486 2487 private void synchronizedEpilogue(int bci, ValueNode currentReturnValue, JavaKind currentReturnValueKind) { 2488 if (method.isSynchronized()) { 2489 if (currentReturnValue != null) { 2490 frameState.push(currentReturnValueKind, currentReturnValue); 2491 } 2492 genMonitorExit(methodSynchronizedObject, currentReturnValue, bci); 2493 assert !frameState.rethrowException(); 2494 finishPrepare(lastInstr, bci); 2495 } 2496 if (frameState.lockDepth(false) != 0) { 2497 throw bailout("unbalanced monitors: too few exits exiting frame"); 2498 } 2499 } 2500 2501 private void createExceptionDispatch(ExceptionDispatchBlock block) { 2502 assert frameState.stackSize() == 1 : frameState; 2503 if (block.handler.isCatchAll()) { 2504 assert block.getSuccessorCount() == 1; 2505 appendGoto(block.getSuccessor(0)); 2506 return; 2507 } 2508 2509 JavaType catchType = block.handler.getCatchType(); 2510 if (graphBuilderConfig.eagerResolving()) { 2511 catchType = lookupType(block.handler.catchTypeCPI(), INSTANCEOF); 2512 } 2513 if (catchType instanceof ResolvedJavaType) { 2514 TypeReference checkedCatchType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) catchType); 2515 2516 if (graphBuilderConfig.getSkippedExceptionTypes() != null) { 2517 for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) { 2518 if (skippedType.isAssignableFrom(checkedCatchType.getType())) { 2519 BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1); 2520 ValueNode exception = frameState.stack[0]; 2521 FixedNode trueSuccessor = graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); 2522 FixedNode nextDispatch = createTarget(nextBlock, frameState); 2523 append(new IfNode(graph.addOrUniqueWithInputs(createInstanceOf(checkedCatchType, exception)), trueSuccessor, nextDispatch, 0)); 2524 return; 2525 } 2526 } 2527 } 2528 2529 BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1); 2530 ValueNode exception = frameState.stack[0]; 2531 /* Anchor for the piNode, which must be before any LoopExit inserted by createTarget. */ 2532 BeginNode piNodeAnchor = graph.add(new BeginNode()); 2533 ObjectStamp checkedStamp = StampFactory.objectNonNull(checkedCatchType); 2534 PiNode piNode = graph.addWithoutUnique(new PiNode(exception, checkedStamp)); 2535 frameState.pop(JavaKind.Object); 2536 frameState.push(JavaKind.Object, piNode); 2537 FixedNode catchSuccessor = createTarget(block.getSuccessor(0), frameState); 2538 frameState.pop(JavaKind.Object); 2539 frameState.push(JavaKind.Object, exception); 2540 FixedNode nextDispatch = createTarget(nextBlock, frameState); 2541 piNodeAnchor.setNext(catchSuccessor); 2542 IfNode ifNode = append(new IfNode(graph.unique(createInstanceOf(checkedCatchType, exception)), piNodeAnchor, nextDispatch, 0.5)); 2543 assert ifNode.trueSuccessor() == piNodeAnchor; 2544 piNode.setGuard(ifNode.trueSuccessor()); 2545 } else { 2546 handleUnresolvedExceptionType(catchType); 2547 } 2548 } 2549 2550 private void appendGoto(BciBlock successor) { 2551 FixedNode targetInstr = createTarget(successor, frameState, true, true); 2552 if (lastInstr != null && lastInstr != targetInstr) { 2553 lastInstr.setNext(targetInstr); 2554 } 2555 } 2556 2557 @SuppressWarnings("try") 2558 protected void iterateBytecodesForBlock(BciBlock block) { 2559 if (block.isLoopHeader) { 2560 // Create the loop header block, which later will merge the backward branches of 2561 // the loop. 2562 controlFlowSplit = true; 2563 LoopBeginNode loopBegin = appendLoopBegin(this.lastInstr); 2564 lastInstr = loopBegin; 2565 2566 // Create phi functions for all local variables and operand stack slots. 2567 frameState.insertLoopPhis(liveness, block.loopId, loopBegin, forceLoopPhis(), stampFromValueForForcedPhis()); 2568 loopBegin.setStateAfter(createFrameState(block.startBci, loopBegin)); 2569 2570 /* 2571 * We have seen all forward branches. All subsequent backward branches will merge to the 2572 * loop header. This ensures that the loop header has exactly one non-loop predecessor. 2573 */ 2574 setFirstInstruction(block, loopBegin); 2575 /* 2576 * We need to preserve the frame state builder of the loop header so that we can merge 2577 * values for phi functions, so make a copy of it. 2578 */ 2579 setEntryState(block, frameState.copy()); 2580 2581 Debug.log(" created loop header %s", loopBegin); 2582 } else if (lastInstr instanceof MergeNode) { 2583 /* 2584 * All inputs of non-loop phi nodes are known by now. We can infer the stamp for the 2585 * phi, so that parsing continues with more precise type information. 2586 */ 2587 frameState.inferPhiStamps((AbstractMergeNode) lastInstr); 2588 } 2589 assert lastInstr.next() == null : "instructions already appended at block " + block; 2590 Debug.log(" frameState: %s", frameState); 2591 2592 lastInstr = finishInstruction(lastInstr, frameState); 2593 2594 int endBCI = stream.endBCI(); 2595 2596 stream.setBCI(block.startBci); 2597 int bci = block.startBci; 2598 BytecodesParsed.add(block.endBci - bci); 2599 2600 /* Reset line number for new block */ 2601 if (graphBuilderConfig.insertFullInfopoints()) { 2602 previousLineNumber = -1; 2603 } 2604 2605 while (bci < endBCI) { 2606 if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) { 2607 currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : -1; 2608 if (currentLineNumber != previousLineNumber) { 2609 genInfoPointNode(InfopointReason.BYTECODE_POSITION, null); 2610 previousLineNumber = currentLineNumber; 2611 } 2612 } 2613 2614 // read the opcode 2615 int opcode = stream.currentBC(); 2616 assert traceState(); 2617 assert traceInstruction(bci, opcode, bci == block.startBci); 2618 if (parent == null && bci == entryBCI) { 2619 if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) { 2620 throw new JsrNotSupportedBailout("OSR into a JSR scope is not supported"); 2621 } 2622 EntryMarkerNode x = append(new EntryMarkerNode()); 2623 frameState.insertProxies(value -> graph.unique(new EntryProxyNode(value, x))); 2624 x.setStateAfter(createFrameState(bci, x)); 2625 } 2626 2627 try (DebugCloseable context = openNodeContext()) { 2628 processBytecode(bci, opcode); 2629 } catch (BailoutException e) { 2630 // Don't wrap bailouts as parser errors 2631 throw e; 2632 } catch (Throwable e) { 2633 throw asParserError(e); 2634 } 2635 2636 if (lastInstr == null || lastInstr.next() != null) { 2637 break; 2638 } 2639 2640 stream.next(); 2641 bci = stream.currentBCI(); 2642 2643 assert block == currentBlock; 2644 assert checkLastInstruction(); 2645 lastInstr = finishInstruction(lastInstr, frameState); 2646 if (bci < endBCI) { 2647 if (bci > block.endBci) { 2648 assert !block.getSuccessor(0).isExceptionEntry; 2649 assert block.numNormalSuccessors() == 1; 2650 // we fell through to the next block, add a goto and break 2651 appendGoto(block.getSuccessor(0)); 2652 break; 2653 } 2654 } 2655 } 2656 } 2657 2658 private DebugCloseable openNodeContext() { 2659 if (graphBuilderConfig.trackNodeSourcePosition() && !parsingIntrinsic()) { 2660 return graph.withNodeSourcePosition(createBytecodePosition()); 2661 } 2662 return null; 2663 } 2664 2665 /* Also a hook for subclasses. */ 2666 protected boolean forceLoopPhis() { 2667 return graph.isOSR(); 2668 } 2669 2670 /* Hook for subclasses. */ 2671 protected boolean stampFromValueForForcedPhis() { 2672 return false; 2673 } 2674 2675 protected boolean checkLastInstruction() { 2676 if (lastInstr instanceof BeginNode) { 2677 // ignore 2678 } else if (lastInstr instanceof StateSplit) { 2679 StateSplit stateSplit = (StateSplit) lastInstr; 2680 if (stateSplit.hasSideEffect()) { 2681 assert stateSplit.stateAfter() != null : "side effect " + lastInstr + " requires a non-null stateAfter"; 2682 } 2683 } 2684 return true; 2685 } 2686 2687 /* Also a hook for subclasses. */ 2688 protected boolean disableLoopSafepoint() { 2689 return parsingIntrinsic(); 2690 } 2691 2692 private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext) { 2693 EndNode preLoopEnd = graph.add(new EndNode()); 2694 LoopBeginNode loopBegin = graph.add(new LoopBeginNode()); 2695 if (disableLoopSafepoint()) { 2696 loopBegin.disableSafepoint(); 2697 } 2698 fixedWithNext.setNext(preLoopEnd); 2699 // Add the single non-loop predecessor of the loop header. 2700 loopBegin.addForwardEnd(preLoopEnd); 2701 return loopBegin; 2702 } 2703 2704 /** 2705 * Hook for subclasses to modify the last instruction or add other instructions. 2706 * 2707 * @param instr The last instruction (= fixed node) which was added. 2708 * @param state The current frame state. 2709 * @return Returns the (new) last instruction. 2710 */ 2711 protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, FrameStateBuilder state) { 2712 return instr; 2713 } 2714 2715 private void genInfoPointNode(InfopointReason reason, ValueNode escapedReturnValue) { 2716 if (!parsingIntrinsic() && graphBuilderConfig.insertFullInfopoints()) { 2717 append(new FullInfopointNode(reason, createFrameState(bci(), null), escapedReturnValue)); 2718 } 2719 } 2720 2721 private boolean traceState() { 2722 if (Debug.isEnabled() && TraceBytecodeParserLevel.getValue(options) >= TRACELEVEL_STATE && Debug.isLogEnabled()) { 2723 frameState.traceState(); 2724 } 2725 return true; 2726 } 2727 2728 protected void genIf(ValueNode x, Condition cond, ValueNode y) { 2729 assert x.getStackKind() == y.getStackKind(); 2730 assert currentBlock.getSuccessorCount() == 2; 2731 BciBlock trueBlock = currentBlock.getSuccessor(0); 2732 BciBlock falseBlock = currentBlock.getSuccessor(1); 2733 2734 if (trueBlock == falseBlock) { 2735 // The target block is the same independent of the condition. 2736 appendGoto(trueBlock); 2737 return; 2738 } 2739 2740 ValueNode a = x; 2741 ValueNode b = y; 2742 2743 // Check whether the condition needs to mirror the operands. 2744 if (cond.canonicalMirror()) { 2745 a = y; 2746 b = x; 2747 } 2748 2749 // Create the logic node for the condition. 2750 LogicNode condition = createLogicNode(cond, a, b); 2751 2752 // Check whether the condition needs to negate the result. 2753 boolean negate = cond.canonicalNegate(); 2754 genIf(condition, negate, trueBlock, falseBlock); 2755 } 2756 2757 protected void genIf(LogicNode conditionInput, boolean negateCondition, BciBlock trueBlockInput, BciBlock falseBlockInput) { 2758 BciBlock trueBlock = trueBlockInput; 2759 BciBlock falseBlock = falseBlockInput; 2760 LogicNode condition = conditionInput; 2761 FrameState stateBefore = null; 2762 ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin(); 2763 if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { 2764 stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); 2765 } 2766 2767 // Remove a logic negation node and fold it into the negate boolean. 2768 boolean negate = negateCondition; 2769 if (condition instanceof LogicNegationNode) { 2770 LogicNegationNode logicNegationNode = (LogicNegationNode) condition; 2771 negate = !negate; 2772 condition = logicNegationNode.getValue(); 2773 } 2774 2775 if (condition instanceof LogicConstantNode) { 2776 genConstantTargetIf(trueBlock, falseBlock, negate, condition); 2777 } else { 2778 if (condition.graph() == null) { 2779 condition = graph.unique(condition); 2780 } 2781 2782 // Need to get probability based on current bci. 2783 double probability = branchProbability(); 2784 2785 if (negate) { 2786 BciBlock tmpBlock = trueBlock; 2787 trueBlock = falseBlock; 2788 falseBlock = tmpBlock; 2789 probability = 1 - probability; 2790 } 2791 2792 if (isNeverExecutedCode(probability)) { 2793 append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, true)); 2794 if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { 2795 profilingPlugin.profileGoto(this, method, bci(), falseBlock.startBci, stateBefore); 2796 } 2797 appendGoto(falseBlock); 2798 return; 2799 } else if (isNeverExecutedCode(1 - probability)) { 2800 append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, false)); 2801 if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { 2802 profilingPlugin.profileGoto(this, method, bci(), trueBlock.startBci, stateBefore); 2803 } 2804 appendGoto(trueBlock); 2805 return; 2806 } 2807 2808 if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { 2809 profilingPlugin.profileIf(this, method, bci(), condition, trueBlock.startBci, falseBlock.startBci, stateBefore); 2810 } 2811 2812 int oldBci = stream.currentBCI(); 2813 int trueBlockInt = checkPositiveIntConstantPushed(trueBlock); 2814 if (trueBlockInt != -1) { 2815 int falseBlockInt = checkPositiveIntConstantPushed(falseBlock); 2816 if (falseBlockInt != -1) { 2817 if (tryGenConditionalForIf(trueBlock, falseBlock, condition, oldBci, trueBlockInt, falseBlockInt)) { 2818 return; 2819 } 2820 } 2821 } 2822 2823 this.controlFlowSplit = true; 2824 FixedNode trueSuccessor = createTarget(trueBlock, frameState, false, false); 2825 FixedNode falseSuccessor = createTarget(falseBlock, frameState, false, true); 2826 ValueNode ifNode = genIfNode(condition, trueSuccessor, falseSuccessor, probability); 2827 postProcessIfNode(ifNode); 2828 append(ifNode); 2829 } 2830 } 2831 2832 /** 2833 * Hook for subclasses to generate custom nodes before an IfNode. 2834 */ 2835 @SuppressWarnings("unused") 2836 protected void postProcessIfNode(ValueNode node) { 2837 } 2838 2839 private boolean tryGenConditionalForIf(BciBlock trueBlock, BciBlock falseBlock, LogicNode condition, int oldBci, int trueBlockInt, int falseBlockInt) { 2840 if (gotoOrFallThroughAfterConstant(trueBlock) && gotoOrFallThroughAfterConstant(falseBlock) && trueBlock.getSuccessor(0) == falseBlock.getSuccessor(0)) { 2841 genConditionalForIf(trueBlock, condition, oldBci, trueBlockInt, falseBlockInt, false); 2842 return true; 2843 } else if (this.parent != null && returnAfterConstant(trueBlock) && returnAfterConstant(falseBlock)) { 2844 genConditionalForIf(trueBlock, condition, oldBci, trueBlockInt, falseBlockInt, true); 2845 return true; 2846 } 2847 return false; 2848 } 2849 2850 private void genConditionalForIf(BciBlock trueBlock, LogicNode condition, int oldBci, int trueBlockInt, int falseBlockInt, boolean genReturn) { 2851 ConstantNode trueValue = graph.unique(ConstantNode.forInt(trueBlockInt)); 2852 ConstantNode falseValue = graph.unique(ConstantNode.forInt(falseBlockInt)); 2853 ValueNode conditionalNode = ConditionalNode.create(condition, trueValue, falseValue); 2854 if (conditionalNode.graph() == null) { 2855 conditionalNode = graph.addOrUnique(conditionalNode); 2856 } 2857 if (genReturn) { 2858 JavaKind returnKind = method.getSignature().getReturnKind().getStackKind(); 2859 this.genReturn(conditionalNode, returnKind); 2860 } else { 2861 frameState.push(JavaKind.Int, conditionalNode); 2862 appendGoto(trueBlock.getSuccessor(0)); 2863 stream.setBCI(oldBci); 2864 } 2865 } 2866 2867 private LogicNode createLogicNode(Condition cond, ValueNode a, ValueNode b) { 2868 LogicNode condition; 2869 assert !a.getStackKind().isNumericFloat(); 2870 if (cond == Condition.EQ || cond == Condition.NE) { 2871 if (a.getStackKind() == JavaKind.Object) { 2872 condition = genObjectEquals(a, b); 2873 } else { 2874 condition = genIntegerEquals(a, b); 2875 } 2876 } else { 2877 assert a.getStackKind() != JavaKind.Object && !cond.isUnsigned(); 2878 condition = genIntegerLessThan(a, b); 2879 } 2880 return condition; 2881 } 2882 2883 private void genConstantTargetIf(BciBlock trueBlock, BciBlock falseBlock, boolean negate, LogicNode condition) { 2884 LogicConstantNode constantLogicNode = (LogicConstantNode) condition; 2885 boolean value = constantLogicNode.getValue(); 2886 if (negate) { 2887 value = !value; 2888 } 2889 BciBlock nextBlock = falseBlock; 2890 if (value) { 2891 nextBlock = trueBlock; 2892 } 2893 int startBci = nextBlock.startBci; 2894 int targetAtStart = stream.readUByte(startBci); 2895 if (targetAtStart == Bytecodes.GOTO && nextBlock.getPredecessorCount() == 1) { 2896 // This is an empty block. Skip it. 2897 BciBlock successorBlock = nextBlock.successors.get(0); 2898 ProfilingPlugin profilingPlugin = graphBuilderConfig.getPlugins().getProfilingPlugin(); 2899 if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { 2900 FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); 2901 profilingPlugin.profileGoto(this, method, bci(), successorBlock.startBci, stateBefore); 2902 } 2903 appendGoto(successorBlock); 2904 assert nextBlock.numNormalSuccessors() == 1; 2905 } else { 2906 ProfilingPlugin profilingPlugin = graphBuilderConfig.getPlugins().getProfilingPlugin(); 2907 if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { 2908 FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); 2909 profilingPlugin.profileGoto(this, method, bci(), nextBlock.startBci, stateBefore); 2910 } 2911 appendGoto(nextBlock); 2912 } 2913 } 2914 2915 private int checkPositiveIntConstantPushed(BciBlock block) { 2916 stream.setBCI(block.startBci); 2917 int currentBC = stream.currentBC(); 2918 if (currentBC >= Bytecodes.ICONST_0 && currentBC <= Bytecodes.ICONST_5) { 2919 int constValue = currentBC - Bytecodes.ICONST_0; 2920 return constValue; 2921 } 2922 return -1; 2923 } 2924 2925 private boolean gotoOrFallThroughAfterConstant(BciBlock block) { 2926 stream.setBCI(block.startBci); 2927 int currentBCI = stream.nextBCI(); 2928 stream.setBCI(currentBCI); 2929 int currentBC = stream.currentBC(); 2930 return stream.currentBCI() > block.endBci || currentBC == Bytecodes.GOTO || currentBC == Bytecodes.GOTO_W; 2931 } 2932 2933 private boolean returnAfterConstant(BciBlock block) { 2934 stream.setBCI(block.startBci); 2935 int currentBCI = stream.nextBCI(); 2936 stream.setBCI(currentBCI); 2937 int currentBC = stream.currentBC(); 2938 return currentBC == Bytecodes.IRETURN; 2939 } 2940 2941 @Override 2942 public StampProvider getStampProvider() { 2943 return stampProvider; 2944 } 2945 2946 @Override 2947 public MetaAccessProvider getMetaAccess() { 2948 return metaAccess; 2949 } 2950 2951 @Override 2952 public void push(JavaKind slotKind, ValueNode value) { 2953 assert value.isAlive(); 2954 frameState.push(slotKind, value); 2955 } 2956 2957 @Override 2958 public ConstantReflectionProvider getConstantReflection() { 2959 return constantReflection; 2960 } 2961 2962 @Override 2963 public ConstantFieldProvider getConstantFieldProvider() { 2964 return constantFieldProvider; 2965 } 2966 2967 /** 2968 * Gets the graph being processed by this builder. 2969 */ 2970 @Override 2971 public StructuredGraph getGraph() { 2972 return graph; 2973 } 2974 2975 @Override 2976 public BytecodeParser getParent() { 2977 return parent; 2978 } 2979 2980 @Override 2981 public IntrinsicContext getIntrinsic() { 2982 return intrinsicContext; 2983 } 2984 2985 @Override 2986 public String toString() { 2987 Formatter fmt = new Formatter(); 2988 BytecodeParser bp = this; 2989 String indent = ""; 2990 while (bp != null) { 2991 if (bp != this) { 2992 fmt.format("%n%s", indent); 2993 } 2994 fmt.format("%s [bci: %d, intrinsic: %s]", bp.code.asStackTraceElement(bp.bci()), bp.bci(), bp.parsingIntrinsic()); 2995 fmt.format("%n%s", new BytecodeDisassembler().disassemble(bp.code, bp.bci(), bp.bci() + 10)); 2996 bp = bp.parent; 2997 indent += " "; 2998 } 2999 return fmt.toString(); 3000 } 3001 3002 @Override 3003 public BailoutException bailout(String string) { 3004 FrameState currentFrameState = createFrameState(bci(), null); 3005 StackTraceElement[] elements = GraphUtil.approxSourceStackTraceElement(currentFrameState); 3006 BailoutException bailout = new PermanentBailoutException(string); 3007 throw GraphUtil.createBailoutException(string, bailout, elements); 3008 } 3009 3010 private FrameState createFrameState(int bci, StateSplit forStateSplit) { 3011 if (currentBlock != null && bci > currentBlock.endBci) { 3012 frameState.clearNonLiveLocals(currentBlock, liveness, false); 3013 } 3014 return frameState.create(bci, forStateSplit); 3015 } 3016 3017 @Override 3018 public void setStateAfter(StateSplit sideEffect) { 3019 assert sideEffect.hasSideEffect(); 3020 FrameState stateAfter = createFrameState(stream.nextBCI(), sideEffect); 3021 sideEffect.setStateAfter(stateAfter); 3022 } 3023 3024 protected NodeSourcePosition createBytecodePosition() { 3025 return frameState.createBytecodePosition(bci()); 3026 } 3027 3028 public void setCurrentFrameState(FrameStateBuilder frameState) { 3029 this.frameState = frameState; 3030 } 3031 3032 protected final BytecodeStream getStream() { 3033 return stream; 3034 } 3035 3036 @Override 3037 public int bci() { 3038 return stream.currentBCI(); 3039 } 3040 3041 public void loadLocal(int index, JavaKind kind) { 3042 ValueNode value = frameState.loadLocal(index, kind); 3043 frameState.push(kind, value); 3044 } 3045 3046 public void loadLocalObject(int index) { 3047 ValueNode value = frameState.loadLocal(index, JavaKind.Object); 3048 3049 int nextBCI = stream.nextBCI(); 3050 int nextBC = stream.readUByte(nextBCI); 3051 if (nextBC == Bytecodes.GETFIELD) { 3052 stream.next(); 3053 genGetField(lookupField(stream.readCPI(), Bytecodes.GETFIELD), value); 3054 } else { 3055 frameState.push(JavaKind.Object, value); 3056 } 3057 } 3058 3059 public void storeLocal(JavaKind kind, int index) { 3060 ValueNode value = frameState.pop(kind); 3061 frameState.storeLocal(index, kind, value); 3062 } 3063 3064 private void genLoadConstant(int cpi, int opcode) { 3065 Object con = lookupConstant(cpi, opcode); 3066 3067 if (con instanceof JavaType) { 3068 // this is a load of class constant which might be unresolved 3069 JavaType type = (JavaType) con; 3070 if (type instanceof ResolvedJavaType) { 3071 frameState.push(JavaKind.Object, appendConstant(getConstantReflection().asJavaClass((ResolvedJavaType) type))); 3072 } else { 3073 handleUnresolvedLoadConstant(type); 3074 } 3075 } else if (con instanceof JavaConstant) { 3076 JavaConstant constant = (JavaConstant) con; 3077 frameState.push(constant.getJavaKind(), appendConstant(constant)); 3078 } else { 3079 throw new Error("lookupConstant returned an object of incorrect type"); 3080 } 3081 } 3082 3083 private void genLoadIndexed(JavaKind kind) { 3084 ValueNode index = frameState.pop(JavaKind.Int); 3085 ValueNode array = emitExplicitExceptions(frameState.pop(JavaKind.Object), index); 3086 3087 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 3088 if (plugin.handleLoadIndexed(this, array, index, kind)) { 3089 return; 3090 } 3091 } 3092 3093 frameState.push(kind, append(genLoadIndexed(array, index, kind))); 3094 } 3095 3096 private void genStoreIndexed(JavaKind kind) { 3097 ValueNode value = frameState.pop(kind); 3098 ValueNode index = frameState.pop(JavaKind.Int); 3099 ValueNode array = emitExplicitExceptions(frameState.pop(JavaKind.Object), index); 3100 3101 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 3102 if (plugin.handleStoreIndexed(this, array, index, kind, value)) { 3103 return; 3104 } 3105 } 3106 3107 genStoreIndexed(array, index, kind, value); 3108 } 3109 3110 private void genArithmeticOp(JavaKind kind, int opcode) { 3111 ValueNode y = frameState.pop(kind); 3112 ValueNode x = frameState.pop(kind); 3113 ValueNode v; 3114 switch (opcode) { 3115 case IADD: 3116 case LADD: 3117 v = genIntegerAdd(x, y); 3118 break; 3119 case FADD: 3120 case DADD: 3121 v = genFloatAdd(x, y); 3122 break; 3123 case ISUB: 3124 case LSUB: 3125 v = genIntegerSub(x, y); 3126 break; 3127 case FSUB: 3128 case DSUB: 3129 v = genFloatSub(x, y); 3130 break; 3131 case IMUL: 3132 case LMUL: 3133 v = genIntegerMul(x, y); 3134 break; 3135 case FMUL: 3136 case DMUL: 3137 v = genFloatMul(x, y); 3138 break; 3139 case FDIV: 3140 case DDIV: 3141 v = genFloatDiv(x, y); 3142 break; 3143 case FREM: 3144 case DREM: 3145 v = genFloatRem(x, y); 3146 break; 3147 default: 3148 throw shouldNotReachHere(); 3149 } 3150 frameState.push(kind, append(v)); 3151 } 3152 3153 private void genIntegerDivOp(JavaKind kind, int opcode) { 3154 ValueNode y = frameState.pop(kind); 3155 ValueNode x = frameState.pop(kind); 3156 ValueNode v; 3157 switch (opcode) { 3158 case IDIV: 3159 case LDIV: 3160 v = genIntegerDiv(x, y); 3161 break; 3162 case IREM: 3163 case LREM: 3164 v = genIntegerRem(x, y); 3165 break; 3166 default: 3167 throw shouldNotReachHere(); 3168 } 3169 frameState.push(kind, append(v)); 3170 } 3171 3172 private void genNegateOp(JavaKind kind) { 3173 ValueNode x = frameState.pop(kind); 3174 frameState.push(kind, append(genNegateOp(x))); 3175 } 3176 3177 private void genShiftOp(JavaKind kind, int opcode) { 3178 ValueNode s = frameState.pop(JavaKind.Int); 3179 ValueNode x = frameState.pop(kind); 3180 ValueNode v; 3181 switch (opcode) { 3182 case ISHL: 3183 case LSHL: 3184 v = genLeftShift(x, s); 3185 break; 3186 case ISHR: 3187 case LSHR: 3188 v = genRightShift(x, s); 3189 break; 3190 case IUSHR: 3191 case LUSHR: 3192 v = genUnsignedRightShift(x, s); 3193 break; 3194 default: 3195 throw shouldNotReachHere(); 3196 } 3197 frameState.push(kind, append(v)); 3198 } 3199 3200 private void genLogicOp(JavaKind kind, int opcode) { 3201 ValueNode y = frameState.pop(kind); 3202 ValueNode x = frameState.pop(kind); 3203 ValueNode v; 3204 switch (opcode) { 3205 case IAND: 3206 case LAND: 3207 v = genAnd(x, y); 3208 break; 3209 case IOR: 3210 case LOR: 3211 v = genOr(x, y); 3212 break; 3213 case IXOR: 3214 case LXOR: 3215 v = genXor(x, y); 3216 break; 3217 default: 3218 throw shouldNotReachHere(); 3219 } 3220 frameState.push(kind, append(v)); 3221 } 3222 3223 private void genCompareOp(JavaKind kind, boolean isUnorderedLess) { 3224 ValueNode y = frameState.pop(kind); 3225 ValueNode x = frameState.pop(kind); 3226 frameState.push(JavaKind.Int, append(genNormalizeCompare(x, y, isUnorderedLess))); 3227 } 3228 3229 private void genFloatConvert(FloatConvert op, JavaKind from, JavaKind to) { 3230 ValueNode input = frameState.pop(from); 3231 frameState.push(to, append(genFloatConvert(op, input))); 3232 } 3233 3234 private void genSignExtend(JavaKind from, JavaKind to) { 3235 ValueNode input = frameState.pop(from); 3236 if (from != from.getStackKind()) { 3237 input = append(genNarrow(input, from.getBitCount())); 3238 } 3239 frameState.push(to, append(genSignExtend(input, to.getBitCount()))); 3240 } 3241 3242 private void genZeroExtend(JavaKind from, JavaKind to) { 3243 ValueNode input = frameState.pop(from); 3244 if (from != from.getStackKind()) { 3245 input = append(genNarrow(input, from.getBitCount())); 3246 } 3247 frameState.push(to, append(genZeroExtend(input, to.getBitCount()))); 3248 } 3249 3250 private void genNarrow(JavaKind from, JavaKind to) { 3251 ValueNode input = frameState.pop(from); 3252 frameState.push(to, append(genNarrow(input, to.getBitCount()))); 3253 } 3254 3255 private void genIncrement() { 3256 int index = getStream().readLocalIndex(); 3257 int delta = getStream().readIncrement(); 3258 ValueNode x = frameState.loadLocal(index, JavaKind.Int); 3259 ValueNode y = appendConstant(JavaConstant.forInt(delta)); 3260 frameState.storeLocal(index, JavaKind.Int, append(genIntegerAdd(x, y))); 3261 } 3262 3263 private void genIfZero(Condition cond) { 3264 ValueNode y = appendConstant(JavaConstant.INT_0); 3265 ValueNode x = frameState.pop(JavaKind.Int); 3266 genIf(x, cond, y); 3267 } 3268 3269 private void genIfNull(Condition cond) { 3270 ValueNode y = appendConstant(JavaConstant.NULL_POINTER); 3271 ValueNode x = frameState.pop(JavaKind.Object); 3272 genIf(x, cond, y); 3273 } 3274 3275 private void genIfSame(JavaKind kind, Condition cond) { 3276 ValueNode y = frameState.pop(kind); 3277 ValueNode x = frameState.pop(kind); 3278 genIf(x, cond, y); 3279 } 3280 3281 protected JavaType lookupType(int cpi, int bytecode) { 3282 maybeEagerlyResolve(cpi, bytecode); 3283 JavaType result = constantPool.lookupType(cpi, bytecode); 3284 assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType; 3285 return result; 3286 } 3287 3288 private JavaMethod lookupMethod(int cpi, int opcode) { 3289 maybeEagerlyResolve(cpi, opcode); 3290 JavaMethod result = constantPool.lookupMethod(cpi, opcode); 3291 /* 3292 * In general, one cannot assume that the declaring class being initialized is useful, since 3293 * the actual concrete receiver may be a different class (except for static calls). Also, 3294 * interfaces are initialized only under special circumstances, so that this assertion would 3295 * often fail for interface calls. 3296 */ 3297 assert !graphBuilderConfig.unresolvedIsError() || 3298 (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result; 3299 return result; 3300 } 3301 3302 private JavaField lookupField(int cpi, int opcode) { 3303 maybeEagerlyResolve(cpi, opcode); 3304 JavaField result = constantPool.lookupField(cpi, method, opcode); 3305 if (graphBuilderConfig.eagerResolving()) { 3306 assert result instanceof ResolvedJavaField : "Not resolved: " + result; 3307 ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass(); 3308 if (!declaringClass.isInitialized()) { 3309 assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass; 3310 declaringClass.initialize(); 3311 } 3312 } 3313 assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; 3314 return result; 3315 } 3316 3317 private Object lookupConstant(int cpi, int opcode) { 3318 maybeEagerlyResolve(cpi, opcode); 3319 Object result = constantPool.lookupConstant(cpi); 3320 assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result; 3321 return result; 3322 } 3323 3324 private void maybeEagerlyResolve(int cpi, int bytecode) { 3325 if (intrinsicContext != null) { 3326 constantPool.loadReferencedType(cpi, bytecode); 3327 } else if (graphBuilderConfig.eagerResolving()) { 3328 /* 3329 * Since we're potentially triggering class initialization here, we need synchronization 3330 * to mitigate the potential for class initialization related deadlock being caused by 3331 * the compiler (e.g., https://github.com/graalvm/graal-core/pull/232/files#r90788550). 3332 */ 3333 synchronized (BytecodeParser.class) { 3334 constantPool.loadReferencedType(cpi, bytecode); 3335 } 3336 } 3337 } 3338 3339 private JavaTypeProfile getProfileForTypeCheck(TypeReference type) { 3340 if (parsingIntrinsic() || profilingInfo == null || !optimisticOpts.useTypeCheckHints(getOptions()) || type.isExact()) { 3341 return null; 3342 } else { 3343 return profilingInfo.getTypeProfile(bci()); 3344 } 3345 } 3346 3347 private void genCheckCast() { 3348 int cpi = getStream().readCPI(); 3349 JavaType type = lookupType(cpi, CHECKCAST); 3350 ValueNode object = frameState.pop(JavaKind.Object); 3351 3352 if (!(type instanceof ResolvedJavaType)) { 3353 handleUnresolvedCheckCast(type, object); 3354 return; 3355 } 3356 TypeReference checkedType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) type); 3357 JavaTypeProfile profile = getProfileForTypeCheck(checkedType); 3358 3359 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 3360 if (plugin.handleCheckCast(this, object, checkedType.getType(), profile)) { 3361 return; 3362 } 3363 } 3364 3365 ValueNode castNode = null; 3366 if (profile != null) { 3367 if (profile.getNullSeen().isFalse()) { 3368 object = nullCheckedValue(object); 3369 ResolvedJavaType singleType = profile.asSingleType(); 3370 if (singleType != null && checkedType.getType().isAssignableFrom(singleType)) { 3371 LogicNode typeCheck = append(createInstanceOf(TypeReference.createExactTrusted(singleType), object, profile)); 3372 if (typeCheck.isTautology()) { 3373 castNode = object; 3374 } else { 3375 FixedGuardNode fixedGuard = append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, false)); 3376 castNode = append(new PiNode(object, StampFactory.objectNonNull(TypeReference.createExactTrusted(singleType)), fixedGuard)); 3377 } 3378 } 3379 } 3380 } 3381 3382 boolean nonNull = ((ObjectStamp) object.stamp()).nonNull(); 3383 if (castNode == null) { 3384 LogicNode condition = genUnique(createInstanceOfAllowNull(checkedType, object, null)); 3385 if (condition.isTautology()) { 3386 castNode = object; 3387 } else { 3388 FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false)); 3389 castNode = append(new PiNode(object, StampFactory.object(checkedType, nonNull), fixedGuard)); 3390 } 3391 } 3392 frameState.push(JavaKind.Object, castNode); 3393 } 3394 3395 private void genInstanceOf() { 3396 int cpi = getStream().readCPI(); 3397 JavaType type = lookupType(cpi, INSTANCEOF); 3398 ValueNode object = frameState.pop(JavaKind.Object); 3399 3400 if (!(type instanceof ResolvedJavaType)) { 3401 handleUnresolvedInstanceOf(type, object); 3402 return; 3403 } 3404 TypeReference resolvedType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) type); 3405 JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); 3406 3407 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 3408 if (plugin.handleInstanceOf(this, object, resolvedType.getType(), profile)) { 3409 return; 3410 } 3411 } 3412 3413 LogicNode instanceOfNode = null; 3414 if (profile != null) { 3415 if (profile.getNullSeen().isFalse()) { 3416 object = nullCheckedValue(object); 3417 ResolvedJavaType singleType = profile.asSingleType(); 3418 if (singleType != null) { 3419 LogicNode typeCheck = append(createInstanceOf(TypeReference.createExactTrusted(singleType), object, profile)); 3420 if (!typeCheck.isTautology()) { 3421 append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile)); 3422 } 3423 instanceOfNode = LogicConstantNode.forBoolean(resolvedType.getType().isAssignableFrom(singleType)); 3424 } 3425 } 3426 } 3427 if (instanceOfNode == null) { 3428 instanceOfNode = createInstanceOf(resolvedType, object, null); 3429 } 3430 LogicNode logicNode = genUnique(instanceOfNode); 3431 3432 int next = getStream().nextBCI(); 3433 int value = getStream().readUByte(next); 3434 if (value == Bytecodes.IFEQ || value == Bytecodes.IFNE) { 3435 getStream().next(); 3436 BciBlock firstSucc = currentBlock.getSuccessor(0); 3437 BciBlock secondSucc = currentBlock.getSuccessor(1); 3438 if (firstSucc != secondSucc) { 3439 genIf(instanceOfNode, value != Bytecodes.IFNE, firstSucc, secondSucc); 3440 } else { 3441 appendGoto(firstSucc); 3442 } 3443 } else { 3444 // Most frequent for value is IRETURN, followed by ISTORE. 3445 frameState.push(JavaKind.Int, append(genConditional(logicNode))); 3446 } 3447 } 3448 3449 void genNewInstance(int cpi) { 3450 JavaType type = lookupType(cpi, NEW); 3451 3452 if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) { 3453 handleUnresolvedNewInstance(type); 3454 return; 3455 } 3456 ResolvedJavaType resolvedType = (ResolvedJavaType) type; 3457 3458 ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes(); 3459 if (skippedExceptionTypes != null) { 3460 for (ResolvedJavaType exceptionType : skippedExceptionTypes) { 3461 if (exceptionType.isAssignableFrom(resolvedType)) { 3462 append(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, RuntimeConstraint)); 3463 return; 3464 } 3465 } 3466 } 3467 3468 ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin(); 3469 if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType)) { 3470 FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); 3471 classInitializationPlugin.apply(this, resolvedType, stateBefore); 3472 } 3473 3474 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 3475 if (plugin.handleNewInstance(this, resolvedType)) { 3476 return; 3477 } 3478 } 3479 3480 frameState.push(JavaKind.Object, append(createNewInstance(resolvedType, true))); 3481 } 3482 3483 /** 3484 * Gets the kind of array elements for the array type code that appears in a 3485 * {@link Bytecodes#NEWARRAY} bytecode. 3486 * 3487 * @param code the array type code 3488 * @return the kind from the array type code 3489 */ 3490 private static Class<?> arrayTypeCodeToClass(int code) { 3491 switch (code) { 3492 case 4: 3493 return boolean.class; 3494 case 5: 3495 return char.class; 3496 case 6: 3497 return float.class; 3498 case 7: 3499 return double.class; 3500 case 8: 3501 return byte.class; 3502 case 9: 3503 return short.class; 3504 case 10: 3505 return int.class; 3506 case 11: 3507 return long.class; 3508 default: 3509 throw new IllegalArgumentException("unknown array type code: " + code); 3510 } 3511 } 3512 3513 private void genNewPrimitiveArray(int typeCode) { 3514 ResolvedJavaType elementType = metaAccess.lookupJavaType(arrayTypeCodeToClass(typeCode)); 3515 ValueNode length = frameState.pop(JavaKind.Int); 3516 3517 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 3518 if (plugin.handleNewArray(this, elementType, length)) { 3519 return; 3520 } 3521 } 3522 3523 frameState.push(JavaKind.Object, append(createNewArray(elementType, length, true))); 3524 } 3525 3526 private void genNewObjectArray(int cpi) { 3527 JavaType type = lookupType(cpi, ANEWARRAY); 3528 3529 if (!(type instanceof ResolvedJavaType)) { 3530 ValueNode length = frameState.pop(JavaKind.Int); 3531 handleUnresolvedNewObjectArray(type, length); 3532 return; 3533 } 3534 3535 ResolvedJavaType resolvedType = (ResolvedJavaType) type; 3536 3537 ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin(); 3538 if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType.getArrayClass())) { 3539 FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); 3540 classInitializationPlugin.apply(this, resolvedType.getArrayClass(), stateBefore); 3541 } 3542 3543 ValueNode length = frameState.pop(JavaKind.Int); 3544 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 3545 if (plugin.handleNewArray(this, resolvedType, length)) { 3546 return; 3547 } 3548 } 3549 3550 frameState.push(JavaKind.Object, append(createNewArray(resolvedType, length, true))); 3551 } 3552 3553 private void genNewMultiArray(int cpi) { 3554 JavaType type = lookupType(cpi, MULTIANEWARRAY); 3555 int rank = getStream().readUByte(bci() + 3); 3556 ValueNode[] dims = new ValueNode[rank]; 3557 3558 if (!(type instanceof ResolvedJavaType)) { 3559 for (int i = rank - 1; i >= 0; i--) { 3560 dims[i] = frameState.pop(JavaKind.Int); 3561 } 3562 handleUnresolvedNewMultiArray(type, dims); 3563 return; 3564 } 3565 ResolvedJavaType resolvedType = (ResolvedJavaType) type; 3566 3567 ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin(); 3568 if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType.getArrayClass())) { 3569 FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); 3570 classInitializationPlugin.apply(this, resolvedType.getArrayClass(), stateBefore); 3571 } 3572 3573 for (int i = rank - 1; i >= 0; i--) { 3574 dims[i] = frameState.pop(JavaKind.Int); 3575 } 3576 3577 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 3578 if (plugin.handleNewMultiArray(this, resolvedType, dims)) { 3579 return; 3580 } 3581 } 3582 3583 frameState.push(JavaKind.Object, append(createNewMultiArray(resolvedType, dims))); 3584 } 3585 3586 private void genGetField(JavaField field) { 3587 genGetField(field, frameState.pop(JavaKind.Object)); 3588 } 3589 3590 private void genGetField(JavaField field, ValueNode receiverInput) { 3591 ValueNode receiver = emitExplicitExceptions(receiverInput); 3592 if (field instanceof ResolvedJavaField) { 3593 ResolvedJavaField resolvedField = (ResolvedJavaField) field; 3594 genGetField(resolvedField, receiver); 3595 } else { 3596 handleUnresolvedLoadField(field, receiver); 3597 } 3598 } 3599 3600 private void genGetField(ResolvedJavaField resolvedField, ValueNode receiver) { 3601 if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) { 3602 graph.recordField(resolvedField); 3603 } 3604 3605 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 3606 if (plugin.handleLoadField(this, receiver, resolvedField)) { 3607 return; 3608 } 3609 } 3610 3611 frameState.push(resolvedField.getJavaKind(), append(genLoadField(receiver, resolvedField))); 3612 if (resolvedField.getDeclaringClass().getName().equals("Ljava/lang/ref/Reference;") && resolvedField.getName().equals("referent")) { 3613 LocationIdentity referentIdentity = new FieldLocationIdentity(resolvedField); 3614 append(new MembarNode(0, referentIdentity)); 3615 } 3616 } 3617 3618 /** 3619 * @param receiver the receiver of an object based operation 3620 * @param index the index of an array based operation that is to be tested for out of bounds. 3621 * This is null for a non-array operation. 3622 * @return the receiver value possibly modified to have a non-null stamp 3623 */ 3624 protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) { 3625 if (needsExplicitException()) { 3626 ValueNode nonNullReceiver = emitExplicitNullCheck(receiver); 3627 ValueNode length = append(genArrayLength(nonNullReceiver)); 3628 emitExplicitBoundsCheck(index, length); 3629 return nonNullReceiver; 3630 } 3631 return receiver; 3632 } 3633 3634 protected ValueNode emitExplicitExceptions(ValueNode receiver) { 3635 if (StampTool.isPointerNonNull(receiver) || !needsExplicitException()) { 3636 return receiver; 3637 } else { 3638 return emitExplicitNullCheck(receiver); 3639 } 3640 } 3641 3642 private boolean needsExplicitException() { 3643 BytecodeExceptionMode exceptionMode = graphBuilderConfig.getBytecodeExceptionMode(); 3644 if (exceptionMode == BytecodeExceptionMode.CheckAll || StressExplicitExceptionCode.getValue(options)) { 3645 return true; 3646 } else if (exceptionMode == BytecodeExceptionMode.Profile && profilingInfo != null) { 3647 return profilingInfo.getExceptionSeen(bci()) == TriState.TRUE; 3648 } 3649 return false; 3650 } 3651 3652 private void genPutField(JavaField field) { 3653 genPutField(field, frameState.pop(field.getJavaKind())); 3654 } 3655 3656 private void genPutField(JavaField field, ValueNode value) { 3657 ValueNode receiver = emitExplicitExceptions(frameState.pop(JavaKind.Object)); 3658 if (field instanceof ResolvedJavaField) { 3659 ResolvedJavaField resolvedField = (ResolvedJavaField) field; 3660 3661 if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) { 3662 graph.recordField(resolvedField); 3663 } 3664 3665 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 3666 if (plugin.handleStoreField(this, receiver, resolvedField, value)) { 3667 return; 3668 } 3669 } 3670 3671 if (resolvedField.isFinal() && method.isConstructor()) { 3672 finalBarrierRequired = true; 3673 } 3674 genStoreField(receiver, resolvedField, value); 3675 } else { 3676 handleUnresolvedStoreField(field, value, receiver); 3677 } 3678 } 3679 3680 private void genGetStatic(JavaField field) { 3681 if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { 3682 handleUnresolvedLoadField(field, null); 3683 return; 3684 } 3685 ResolvedJavaField resolvedField = (ResolvedJavaField) field; 3686 3687 if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) { 3688 graph.recordField(resolvedField); 3689 } 3690 3691 /* 3692 * Javac does not allow use of "$assertionsDisabled" for a field name but Eclipse does, in 3693 * which case a suffix is added to the generated field. 3694 */ 3695 if ((parsingIntrinsic() || graphBuilderConfig.omitAssertions()) && resolvedField.isSynthetic() && resolvedField.getName().startsWith("$assertionsDisabled")) { 3696 frameState.push(field.getJavaKind(), ConstantNode.forBoolean(true, graph)); 3697 return; 3698 } 3699 3700 ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin(); 3701 if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedField.getDeclaringClass())) { 3702 FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); 3703 classInitializationPlugin.apply(this, resolvedField.getDeclaringClass(), stateBefore); 3704 } 3705 3706 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 3707 if (plugin.handleLoadStaticField(this, resolvedField)) { 3708 return; 3709 } 3710 } 3711 3712 frameState.push(field.getJavaKind(), append(genLoadField(null, resolvedField))); 3713 } 3714 3715 private void genPutStatic(JavaField field) { 3716 ValueNode value = frameState.pop(field.getJavaKind()); 3717 if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { 3718 handleUnresolvedStoreField(field, value, null); 3719 return; 3720 } 3721 ResolvedJavaField resolvedField = (ResolvedJavaField) field; 3722 3723 if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) { 3724 graph.recordField(resolvedField); 3725 } 3726 3727 ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin(); 3728 if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedField.getDeclaringClass())) { 3729 FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); 3730 classInitializationPlugin.apply(this, resolvedField.getDeclaringClass(), stateBefore); 3731 } 3732 3733 for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { 3734 if (plugin.handleStoreStaticField(this, resolvedField, value)) { 3735 return; 3736 } 3737 } 3738 3739 genStoreField(null, resolvedField, value); 3740 } 3741 3742 private double[] switchProbability(int numberOfCases, int bci) { 3743 double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci)); 3744 if (prob != null) { 3745 assert prob.length == numberOfCases; 3746 } else { 3747 Debug.log("Missing probability (switch) in %s at bci %d", method, bci); 3748 prob = new double[numberOfCases]; 3749 for (int i = 0; i < numberOfCases; i++) { 3750 prob[i] = 1.0d / numberOfCases; 3751 } 3752 } 3753 assert allPositive(prob); 3754 return prob; 3755 } 3756 3757 private static boolean allPositive(double[] a) { 3758 for (double d : a) { 3759 if (d < 0) { 3760 return false; 3761 } 3762 } 3763 return true; 3764 } 3765 3766 static class SuccessorInfo { 3767 final int blockIndex; 3768 int actualIndex; 3769 3770 SuccessorInfo(int blockSuccessorIndex) { 3771 this.blockIndex = blockSuccessorIndex; 3772 actualIndex = -1; 3773 } 3774 } 3775 3776 private void genSwitch(BytecodeSwitch bs) { 3777 int bci = bci(); 3778 ValueNode value = frameState.pop(JavaKind.Int); 3779 3780 int nofCases = bs.numberOfCases(); 3781 double[] keyProbabilities = switchProbability(nofCases + 1, bci); 3782 3783 EconomicMap<Integer, SuccessorInfo> bciToBlockSuccessorIndex = EconomicMap.create(Equivalence.DEFAULT); 3784 for (int i = 0; i < currentBlock.getSuccessorCount(); i++) { 3785 assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci); 3786 bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i)); 3787 } 3788 3789 ArrayList<BciBlock> actualSuccessors = new ArrayList<>(); 3790 int[] keys = new int[nofCases]; 3791 int[] keySuccessors = new int[nofCases + 1]; 3792 int deoptSuccessorIndex = -1; 3793 int nextSuccessorIndex = 0; 3794 boolean constantValue = value.isConstant(); 3795 for (int i = 0; i < nofCases + 1; i++) { 3796 if (i < nofCases) { 3797 keys[i] = bs.keyAt(i); 3798 } 3799 3800 if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) { 3801 if (deoptSuccessorIndex < 0) { 3802 deoptSuccessorIndex = nextSuccessorIndex++; 3803 actualSuccessors.add(null); 3804 } 3805 keySuccessors[i] = deoptSuccessorIndex; 3806 } else { 3807 int targetBci = i >= nofCases ? bs.defaultTarget() : bs.targetAt(i); 3808 SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci); 3809 if (info.actualIndex < 0) { 3810 info.actualIndex = nextSuccessorIndex++; 3811 actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex)); 3812 } 3813 keySuccessors[i] = info.actualIndex; 3814 } 3815 } 3816 3817 genIntegerSwitch(value, actualSuccessors, keys, keyProbabilities, keySuccessors); 3818 3819 } 3820 3821 protected boolean isNeverExecutedCode(double probability) { 3822 return probability == 0 && optimisticOpts.removeNeverExecutedCode(getOptions()); 3823 } 3824 3825 protected double branchProbability() { 3826 if (profilingInfo == null) { 3827 return 0.5; 3828 } 3829 assert assertAtIfBytecode(); 3830 double probability = profilingInfo.getBranchTakenProbability(bci()); 3831 if (probability < 0) { 3832 assert probability == -1 : "invalid probability"; 3833 Debug.log("missing probability in %s at bci %d", code, bci()); 3834 probability = 0.5; 3835 } 3836 3837 if (!optimisticOpts.removeNeverExecutedCode(getOptions())) { 3838 if (probability == 0) { 3839 probability = 0.0000001; 3840 } else if (probability == 1) { 3841 probability = 0.999999; 3842 } 3843 } 3844 return probability; 3845 } 3846 3847 private boolean assertAtIfBytecode() { 3848 int bytecode = stream.currentBC(); 3849 switch (bytecode) { 3850 case IFEQ: 3851 case IFNE: 3852 case IFLT: 3853 case IFGE: 3854 case IFGT: 3855 case IFLE: 3856 case IF_ICMPEQ: 3857 case IF_ICMPNE: 3858 case IF_ICMPLT: 3859 case IF_ICMPGE: 3860 case IF_ICMPGT: 3861 case IF_ICMPLE: 3862 case IF_ACMPEQ: 3863 case IF_ACMPNE: 3864 case IFNULL: 3865 case IFNONNULL: 3866 return true; 3867 } 3868 assert false : String.format("%x is not an if bytecode", bytecode); 3869 return true; 3870 } 3871 3872 public final void processBytecode(int bci, int opcode) { 3873 int cpi; 3874 3875 // @formatter:off 3876 // Checkstyle: stop 3877 switch (opcode) { 3878 case NOP : /* nothing to do */ break; 3879 case ACONST_NULL : frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER)); break; 3880 case ICONST_M1 : // fall through 3881 case ICONST_0 : // fall through 3882 case ICONST_1 : // fall through 3883 case ICONST_2 : // fall through 3884 case ICONST_3 : // fall through 3885 case ICONST_4 : // fall through 3886 case ICONST_5 : frameState.push(JavaKind.Int, appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break; 3887 case LCONST_0 : // fall through 3888 case LCONST_1 : frameState.push(JavaKind.Long, appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break; 3889 case FCONST_0 : // fall through 3890 case FCONST_1 : // fall through 3891 case FCONST_2 : frameState.push(JavaKind.Float, appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break; 3892 case DCONST_0 : // fall through 3893 case DCONST_1 : frameState.push(JavaKind.Double, appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break; 3894 case BIPUSH : frameState.push(JavaKind.Int, appendConstant(JavaConstant.forInt(stream.readByte()))); break; 3895 case SIPUSH : frameState.push(JavaKind.Int, appendConstant(JavaConstant.forInt(stream.readShort()))); break; 3896 case LDC : // fall through 3897 case LDC_W : // fall through 3898 case LDC2_W : genLoadConstant(stream.readCPI(), opcode); break; 3899 case ILOAD : loadLocal(stream.readLocalIndex(), JavaKind.Int); break; 3900 case LLOAD : loadLocal(stream.readLocalIndex(), JavaKind.Long); break; 3901 case FLOAD : loadLocal(stream.readLocalIndex(), JavaKind.Float); break; 3902 case DLOAD : loadLocal(stream.readLocalIndex(), JavaKind.Double); break; 3903 case ALOAD : loadLocalObject(stream.readLocalIndex()); break; 3904 case ILOAD_0 : // fall through 3905 case ILOAD_1 : // fall through 3906 case ILOAD_2 : // fall through 3907 case ILOAD_3 : loadLocal(opcode - ILOAD_0, JavaKind.Int); break; 3908 case LLOAD_0 : // fall through 3909 case LLOAD_1 : // fall through 3910 case LLOAD_2 : // fall through 3911 case LLOAD_3 : loadLocal(opcode - LLOAD_0, JavaKind.Long); break; 3912 case FLOAD_0 : // fall through 3913 case FLOAD_1 : // fall through 3914 case FLOAD_2 : // fall through 3915 case FLOAD_3 : loadLocal(opcode - FLOAD_0, JavaKind.Float); break; 3916 case DLOAD_0 : // fall through 3917 case DLOAD_1 : // fall through 3918 case DLOAD_2 : // fall through 3919 case DLOAD_3 : loadLocal(opcode - DLOAD_0, JavaKind.Double); break; 3920 case ALOAD_0 : // fall through 3921 case ALOAD_1 : // fall through 3922 case ALOAD_2 : // fall through 3923 case ALOAD_3 : loadLocalObject(opcode - ALOAD_0); break; 3924 case IALOAD : genLoadIndexed(JavaKind.Int ); break; 3925 case LALOAD : genLoadIndexed(JavaKind.Long ); break; 3926 case FALOAD : genLoadIndexed(JavaKind.Float ); break; 3927 case DALOAD : genLoadIndexed(JavaKind.Double); break; 3928 case AALOAD : genLoadIndexed(JavaKind.Object); break; 3929 case BALOAD : genLoadIndexed(JavaKind.Byte ); break; 3930 case CALOAD : genLoadIndexed(JavaKind.Char ); break; 3931 case SALOAD : genLoadIndexed(JavaKind.Short ); break; 3932 case ISTORE : storeLocal(JavaKind.Int, stream.readLocalIndex()); break; 3933 case LSTORE : storeLocal(JavaKind.Long, stream.readLocalIndex()); break; 3934 case FSTORE : storeLocal(JavaKind.Float, stream.readLocalIndex()); break; 3935 case DSTORE : storeLocal(JavaKind.Double, stream.readLocalIndex()); break; 3936 case ASTORE : storeLocal(JavaKind.Object, stream.readLocalIndex()); break; 3937 case ISTORE_0 : // fall through 3938 case ISTORE_1 : // fall through 3939 case ISTORE_2 : // fall through 3940 case ISTORE_3 : storeLocal(JavaKind.Int, opcode - ISTORE_0); break; 3941 case LSTORE_0 : // fall through 3942 case LSTORE_1 : // fall through 3943 case LSTORE_2 : // fall through 3944 case LSTORE_3 : storeLocal(JavaKind.Long, opcode - LSTORE_0); break; 3945 case FSTORE_0 : // fall through 3946 case FSTORE_1 : // fall through 3947 case FSTORE_2 : // fall through 3948 case FSTORE_3 : storeLocal(JavaKind.Float, opcode - FSTORE_0); break; 3949 case DSTORE_0 : // fall through 3950 case DSTORE_1 : // fall through 3951 case DSTORE_2 : // fall through 3952 case DSTORE_3 : storeLocal(JavaKind.Double, opcode - DSTORE_0); break; 3953 case ASTORE_0 : // fall through 3954 case ASTORE_1 : // fall through 3955 case ASTORE_2 : // fall through 3956 case ASTORE_3 : storeLocal(JavaKind.Object, opcode - ASTORE_0); break; 3957 case IASTORE : genStoreIndexed(JavaKind.Int ); break; 3958 case LASTORE : genStoreIndexed(JavaKind.Long ); break; 3959 case FASTORE : genStoreIndexed(JavaKind.Float ); break; 3960 case DASTORE : genStoreIndexed(JavaKind.Double); break; 3961 case AASTORE : genStoreIndexed(JavaKind.Object); break; 3962 case BASTORE : genStoreIndexed(JavaKind.Byte ); break; 3963 case CASTORE : genStoreIndexed(JavaKind.Char ); break; 3964 case SASTORE : genStoreIndexed(JavaKind.Short ); break; 3965 case POP : // fall through 3966 case POP2 : // fall through 3967 case DUP : // fall through 3968 case DUP_X1 : // fall through 3969 case DUP_X2 : // fall through 3970 case DUP2 : // fall through 3971 case DUP2_X1 : // fall through 3972 case DUP2_X2 : // fall through 3973 case SWAP : frameState.stackOp(opcode); break; 3974 case IADD : // fall through 3975 case ISUB : // fall through 3976 case IMUL : genArithmeticOp(JavaKind.Int, opcode); break; 3977 case IDIV : // fall through 3978 case IREM : genIntegerDivOp(JavaKind.Int, opcode); break; 3979 case LADD : // fall through 3980 case LSUB : // fall through 3981 case LMUL : genArithmeticOp(JavaKind.Long, opcode); break; 3982 case LDIV : // fall through 3983 case LREM : genIntegerDivOp(JavaKind.Long, opcode); break; 3984 case FADD : // fall through 3985 case FSUB : // fall through 3986 case FMUL : // fall through 3987 case FDIV : // fall through 3988 case FREM : genArithmeticOp(JavaKind.Float, opcode); break; 3989 case DADD : // fall through 3990 case DSUB : // fall through 3991 case DMUL : // fall through 3992 case DDIV : // fall through 3993 case DREM : genArithmeticOp(JavaKind.Double, opcode); break; 3994 case INEG : genNegateOp(JavaKind.Int); break; 3995 case LNEG : genNegateOp(JavaKind.Long); break; 3996 case FNEG : genNegateOp(JavaKind.Float); break; 3997 case DNEG : genNegateOp(JavaKind.Double); break; 3998 case ISHL : // fall through 3999 case ISHR : // fall through 4000 case IUSHR : genShiftOp(JavaKind.Int, opcode); break; 4001 case IAND : // fall through 4002 case IOR : // fall through 4003 case IXOR : genLogicOp(JavaKind.Int, opcode); break; 4004 case LSHL : // fall through 4005 case LSHR : // fall through 4006 case LUSHR : genShiftOp(JavaKind.Long, opcode); break; 4007 case LAND : // fall through 4008 case LOR : // fall through 4009 case LXOR : genLogicOp(JavaKind.Long, opcode); break; 4010 case IINC : genIncrement(); break; 4011 case I2F : genFloatConvert(FloatConvert.I2F, JavaKind.Int, JavaKind.Float); break; 4012 case I2D : genFloatConvert(FloatConvert.I2D, JavaKind.Int, JavaKind.Double); break; 4013 case L2F : genFloatConvert(FloatConvert.L2F, JavaKind.Long, JavaKind.Float); break; 4014 case L2D : genFloatConvert(FloatConvert.L2D, JavaKind.Long, JavaKind.Double); break; 4015 case F2I : genFloatConvert(FloatConvert.F2I, JavaKind.Float, JavaKind.Int); break; 4016 case F2L : genFloatConvert(FloatConvert.F2L, JavaKind.Float, JavaKind.Long); break; 4017 case F2D : genFloatConvert(FloatConvert.F2D, JavaKind.Float, JavaKind.Double); break; 4018 case D2I : genFloatConvert(FloatConvert.D2I, JavaKind.Double, JavaKind.Int); break; 4019 case D2L : genFloatConvert(FloatConvert.D2L, JavaKind.Double, JavaKind.Long); break; 4020 case D2F : genFloatConvert(FloatConvert.D2F, JavaKind.Double, JavaKind.Float); break; 4021 case L2I : genNarrow(JavaKind.Long, JavaKind.Int); break; 4022 case I2L : genSignExtend(JavaKind.Int, JavaKind.Long); break; 4023 case I2B : genSignExtend(JavaKind.Byte, JavaKind.Int); break; 4024 case I2S : genSignExtend(JavaKind.Short, JavaKind.Int); break; 4025 case I2C : genZeroExtend(JavaKind.Char, JavaKind.Int); break; 4026 case LCMP : genCompareOp(JavaKind.Long, false); break; 4027 case FCMPL : genCompareOp(JavaKind.Float, true); break; 4028 case FCMPG : genCompareOp(JavaKind.Float, false); break; 4029 case DCMPL : genCompareOp(JavaKind.Double, true); break; 4030 case DCMPG : genCompareOp(JavaKind.Double, false); break; 4031 case IFEQ : genIfZero(Condition.EQ); break; 4032 case IFNE : genIfZero(Condition.NE); break; 4033 case IFLT : genIfZero(Condition.LT); break; 4034 case IFGE : genIfZero(Condition.GE); break; 4035 case IFGT : genIfZero(Condition.GT); break; 4036 case IFLE : genIfZero(Condition.LE); break; 4037 case IF_ICMPEQ : genIfSame(JavaKind.Int, Condition.EQ); break; 4038 case IF_ICMPNE : genIfSame(JavaKind.Int, Condition.NE); break; 4039 case IF_ICMPLT : genIfSame(JavaKind.Int, Condition.LT); break; 4040 case IF_ICMPGE : genIfSame(JavaKind.Int, Condition.GE); break; 4041 case IF_ICMPGT : genIfSame(JavaKind.Int, Condition.GT); break; 4042 case IF_ICMPLE : genIfSame(JavaKind.Int, Condition.LE); break; 4043 case IF_ACMPEQ : genIfSame(JavaKind.Object, Condition.EQ); break; 4044 case IF_ACMPNE : genIfSame(JavaKind.Object, Condition.NE); break; 4045 case GOTO : genGoto(); break; 4046 case JSR : genJsr(stream.readBranchDest()); break; 4047 case RET : genRet(stream.readLocalIndex()); break; 4048 case TABLESWITCH : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break; 4049 case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break; 4050 case IRETURN : genReturn(frameState.pop(JavaKind.Int), JavaKind.Int); break; 4051 case LRETURN : genReturn(frameState.pop(JavaKind.Long), JavaKind.Long); break; 4052 case FRETURN : genReturn(frameState.pop(JavaKind.Float), JavaKind.Float); break; 4053 case DRETURN : genReturn(frameState.pop(JavaKind.Double), JavaKind.Double); break; 4054 case ARETURN : genReturn(frameState.pop(JavaKind.Object), JavaKind.Object); break; 4055 case RETURN : genReturn(null, JavaKind.Void); break; 4056 case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; 4057 case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; 4058 case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; 4059 case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; 4060 case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; 4061 case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; 4062 case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; 4063 case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; 4064 case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; 4065 case NEW : genNewInstance(stream.readCPI()); break; 4066 case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; 4067 case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; 4068 case ARRAYLENGTH : genArrayLength(); break; 4069 case ATHROW : genThrow(); break; 4070 case CHECKCAST : genCheckCast(); break; 4071 case INSTANCEOF : genInstanceOf(); break; 4072 case MONITORENTER : genMonitorEnter(frameState.pop(JavaKind.Object), stream.nextBCI()); break; 4073 case MONITOREXIT : genMonitorExit(frameState.pop(JavaKind.Object), null, stream.nextBCI()); break; 4074 case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; 4075 case IFNULL : genIfNull(Condition.EQ); break; 4076 case IFNONNULL : genIfNull(Condition.NE); break; 4077 case GOTO_W : genGoto(); break; 4078 case JSR_W : genJsr(stream.readBranchDest()); break; 4079 case BREAKPOINT : throw new PermanentBailoutException("concurrent setting of breakpoint"); 4080 default : throw new PermanentBailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci); 4081 } 4082 // @formatter:on 4083 // Checkstyle: resume 4084 } 4085 4086 private void genArrayLength() { 4087 ValueNode array = emitExplicitExceptions(frameState.pop(JavaKind.Object)); 4088 frameState.push(JavaKind.Int, append(genArrayLength(array))); 4089 } 4090 4091 @Override 4092 public ResolvedJavaMethod getMethod() { 4093 return method; 4094 } 4095 4096 @Override 4097 public Bytecode getCode() { 4098 return code; 4099 } 4100 4101 public FrameStateBuilder getFrameStateBuilder() { 4102 return frameState; 4103 } 4104 4105 protected boolean traceInstruction(int bci, int opcode, boolean blockStart) { 4106 if (Debug.isEnabled() && TraceBytecodeParserLevel.getValue(options) >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) { 4107 traceInstructionHelper(bci, opcode, blockStart); 4108 } 4109 return true; 4110 } 4111 4112 private void traceInstructionHelper(int bci, int opcode, boolean blockStart) { 4113 StringBuilder sb = new StringBuilder(40); 4114 sb.append(blockStart ? '+' : '|'); 4115 if (bci < 10) { 4116 sb.append(" "); 4117 } else if (bci < 100) { 4118 sb.append(' '); 4119 } 4120 sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode)); 4121 for (int i = bci + 1; i < stream.nextBCI(); ++i) { 4122 sb.append(' ').append(stream.readUByte(i)); 4123 } 4124 if (!currentBlock.getJsrScope().isEmpty()) { 4125 sb.append(' ').append(currentBlock.getJsrScope()); 4126 } 4127 Debug.log("%s", sb); 4128 } 4129 4130 @Override 4131 public boolean parsingIntrinsic() { 4132 return intrinsicContext != null; 4133 } 4134 4135 @Override 4136 public BytecodeParser getNonIntrinsicAncestor() { 4137 BytecodeParser ancestor = parent; 4138 while (ancestor != null && ancestor.parsingIntrinsic()) { 4139 ancestor = ancestor.parent; 4140 } 4141 return ancestor; 4142 } 4143 4144 static String nSpaces(int n) { 4145 return n == 0 ? "" : format("%" + n + "s", ""); 4146 } 4147} 4148