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