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