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