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