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