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