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