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