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