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