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