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