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