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