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