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