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