25 import static org.graalvm.compiler.bytecode.Bytecodes.DUP;
26 import static org.graalvm.compiler.bytecode.Bytecodes.DUP2;
27 import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X1;
28 import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X2;
29 import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X1;
30 import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X2;
31 import static org.graalvm.compiler.bytecode.Bytecodes.POP;
32 import static org.graalvm.compiler.bytecode.Bytecodes.POP2;
33 import static org.graalvm.compiler.bytecode.Bytecodes.SWAP;
34 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
35 import static org.graalvm.compiler.java.BytecodeParserOptions.HideSubstitutionStates;
36 import static org.graalvm.compiler.nodes.FrameState.TWO_SLOT_MARKER;
37
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
41 import java.util.function.Function;
42
43 import org.graalvm.compiler.bytecode.Bytecode;
44 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
45 import org.graalvm.compiler.common.PermanentBailoutException;
46 import org.graalvm.compiler.core.common.type.StampFactory;
47 import org.graalvm.compiler.core.common.type.StampPair;
48 import org.graalvm.compiler.debug.Debug;
49 import org.graalvm.compiler.graph.NodeSourcePosition;
50 import org.graalvm.compiler.java.BciBlockMapping.BciBlock;
51 import org.graalvm.compiler.nodeinfo.Verbosity;
52 import org.graalvm.compiler.nodes.AbstractMergeNode;
53 import org.graalvm.compiler.nodes.ConstantNode;
54 import org.graalvm.compiler.nodes.FrameState;
55 import org.graalvm.compiler.nodes.LoopBeginNode;
56 import org.graalvm.compiler.nodes.LoopExitNode;
57 import org.graalvm.compiler.nodes.ParameterNode;
58 import org.graalvm.compiler.nodes.PhiNode;
59 import org.graalvm.compiler.nodes.ProxyNode;
60 import org.graalvm.compiler.nodes.StateSplit;
61 import org.graalvm.compiler.nodes.StructuredGraph;
62 import org.graalvm.compiler.nodes.ValueNode;
63 import org.graalvm.compiler.nodes.ValuePhiNode;
64 import org.graalvm.compiler.nodes.calc.FloatingNode;
65 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
82
83 private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
84 private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
85
86 private final BytecodeParser parser;
87 private final GraphBuilderTool tool;
88 private final Bytecode code;
89 private int stackSize;
90 protected final ValueNode[] locals;
91 protected final ValueNode[] stack;
92 private ValueNode[] lockedObjects;
93 private boolean canVerifyKind;
94
95 /**
96 * @see BytecodeFrame#rethrowException
97 */
98 private boolean rethrowException;
99
100 private MonitorIdNode[] monitorIds;
101 private final StructuredGraph graph;
102 private FrameState outerFrameState;
103
104 /**
105 * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more
106 * than one when the current block contains no side-effects but merging predecessor blocks do.
107 */
108 private List<StateSplit> sideEffects;
109
110 private JavaConstant constantReceiver;
111
112 /**
113 * Creates a new frame state builder for the given method and the given target graph.
114 *
115 * @param method the method whose frame is simulated
116 * @param graph the target graph of Graal nodes created by the builder
117 */
118 public FrameStateBuilder(GraphBuilderTool tool, ResolvedJavaMethod method, StructuredGraph graph) {
119 this(tool, new ResolvedJavaMethodBytecode(method), graph);
120 }
121
125 *
126 * @param code the bytecode in which the frame exists
127 * @param graph the target graph of Graal nodes created by the builder
128 */
129 public FrameStateBuilder(GraphBuilderTool tool, Bytecode code, StructuredGraph graph) {
130 this.tool = tool;
131 if (tool instanceof BytecodeParser) {
132 this.parser = (BytecodeParser) tool;
133 } else {
134 this.parser = null;
135 }
136 this.code = code;
137 this.locals = allocateArray(code.getMaxLocals());
138 this.stack = allocateArray(Math.max(1, code.getMaxStackSize()));
139 this.lockedObjects = allocateArray(0);
140
141 assert graph != null;
142
143 this.monitorIds = EMPTY_MONITOR_ARRAY;
144 this.graph = graph;
145 this.canVerifyKind = true;
146 }
147
148 public void disableKindVerification() {
149 canVerifyKind = false;
150 }
151
152 public void initializeFromArgumentsArray(ValueNode[] arguments) {
153
154 int javaIndex = 0;
155 int index = 0;
156 if (!getMethod().isStatic()) {
157 // set the receiver
158 locals[javaIndex] = arguments[index];
159 javaIndex = 1;
160 index = 1;
161 constantReceiver = locals[0].asJavaConstant();
162 }
163 Signature sig = getMethod().getSignature();
164 int max = sig.getParameterCount(false);
246 index++;
247 }
248 }
249
250 private FrameStateBuilder(FrameStateBuilder other) {
251 this.parser = other.parser;
252 this.tool = other.tool;
253 this.code = other.code;
254 this.stackSize = other.stackSize;
255 this.locals = other.locals.clone();
256 this.stack = other.stack.clone();
257 this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone();
258 this.rethrowException = other.rethrowException;
259 this.canVerifyKind = other.canVerifyKind;
260
261 assert locals.length == code.getMaxLocals();
262 assert stack.length == Math.max(1, code.getMaxStackSize());
263
264 assert other.graph != null;
265 graph = other.graph;
266 monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone();
267
268 assert locals.length == code.getMaxLocals();
269 assert stack.length == Math.max(1, code.getMaxStackSize());
270 assert lockedObjects.length == monitorIds.length;
271 }
272
273 private static ValueNode[] allocateArray(int length) {
274 return length == 0 ? EMPTY_ARRAY : new ValueNode[length];
275 }
276
277 public ResolvedJavaMethod getMethod() {
278 return code.getMethod();
279 }
280
281 @Override
282 public String toString() {
283 StringBuilder sb = new StringBuilder();
284 sb.append("[locals: [");
285 for (int i = 0; i < locals.length; i++) {
330 if (pushedValues != null) {
331 assert pushedSlotKinds.length == pushedValues.length;
332 int stackSizeToRestore = stackSize;
333 for (int i = 0; i < pushedValues.length; i++) {
334 push(pushedSlotKinds[i], pushedValues[i]);
335 }
336 FrameState res = graph.add(new FrameState(outerFrameState, code, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
337 stackSize = stackSizeToRestore;
338 return res;
339 } else {
340 if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
341 assert outerFrameState == null;
342 clearLocals();
343 }
344 return graph.add(new FrameState(outerFrameState, code, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
345 }
346 }
347
348 public NodeSourcePosition createBytecodePosition(int bci) {
349 BytecodeParser parent = parser.getParent();
350 if (HideSubstitutionStates.getValue()) {
351 if (parser.parsingIntrinsic()) {
352 // Attribute to the method being replaced
353 return new NodeSourcePosition(constantReceiver, parent.getFrameStateBuilder().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1);
354 }
355 // Skip intrinsic frames
356 parent = parser.getNonIntrinsicAncestor();
357 }
358 return create(null, constantReceiver, bci, parent);
359 }
360
361 private NodeSourcePosition create(NodeSourcePosition o, JavaConstant receiver, int bci, BytecodeParser parent) {
362 NodeSourcePosition outer = o;
363 if (outer == null && parent != null) {
364 outer = parent.getFrameStateBuilder().createBytecodePosition(parent.bci());
365 }
366 if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
367 return FrameState.toSourcePosition(outerFrameState);
368 }
369 if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
370 throw shouldNotReachHere();
607 if (stack[i] == value) {
608 return true;
609 }
610 }
611 assert lockedObjects.length == monitorIds.length;
612 for (int i = 0; i < lockedObjects.length; i++) {
613 if (lockedObjects[i] == value || monitorIds[i] == value) {
614 return true;
615 }
616 }
617 return false;
618 }
619
620 public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
621 /*
622 * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
623 * remove it for normal compilations, but not for OSR compilations - otherwise dead object
624 * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
625 * Kind.Illegal, because the conflicting branch might not have been parsed.
626 */
627 if (!parser.graphBuilderConfig.clearNonLiveLocals()) {
628 return;
629 }
630 if (liveIn) {
631 for (int i = 0; i < locals.length; i++) {
632 if (!liveness.localIsLiveIn(block, i)) {
633 assert locals[i] != TWO_SLOT_MARKER || locals[i - 1] == null : "Clearing of second slot must have cleared the first slot too";
634 locals[i] = null;
635 }
636 }
637 } else {
638 for (int i = 0; i < locals.length; i++) {
639 if (!liveness.localIsLiveOut(block, i)) {
640 assert locals[i] != TWO_SLOT_MARKER || locals[i - 1] == null : "Clearing of second slot must have cleared the first slot too";
641 locals[i] = null;
642 }
643 }
644 }
645 }
646
647 /**
|
25 import static org.graalvm.compiler.bytecode.Bytecodes.DUP;
26 import static org.graalvm.compiler.bytecode.Bytecodes.DUP2;
27 import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X1;
28 import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X2;
29 import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X1;
30 import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X2;
31 import static org.graalvm.compiler.bytecode.Bytecodes.POP;
32 import static org.graalvm.compiler.bytecode.Bytecodes.POP2;
33 import static org.graalvm.compiler.bytecode.Bytecodes.SWAP;
34 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
35 import static org.graalvm.compiler.java.BytecodeParserOptions.HideSubstitutionStates;
36 import static org.graalvm.compiler.nodes.FrameState.TWO_SLOT_MARKER;
37
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
41 import java.util.function.Function;
42
43 import org.graalvm.compiler.bytecode.Bytecode;
44 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
45 import org.graalvm.compiler.core.common.PermanentBailoutException;
46 import org.graalvm.compiler.core.common.GraalOptions;
47 import org.graalvm.compiler.core.common.type.StampFactory;
48 import org.graalvm.compiler.core.common.type.StampPair;
49 import org.graalvm.compiler.debug.Debug;
50 import org.graalvm.compiler.graph.NodeSourcePosition;
51 import org.graalvm.compiler.java.BciBlockMapping.BciBlock;
52 import org.graalvm.compiler.nodeinfo.Verbosity;
53 import org.graalvm.compiler.nodes.AbstractMergeNode;
54 import org.graalvm.compiler.nodes.ConstantNode;
55 import org.graalvm.compiler.nodes.FrameState;
56 import org.graalvm.compiler.nodes.LoopBeginNode;
57 import org.graalvm.compiler.nodes.LoopExitNode;
58 import org.graalvm.compiler.nodes.ParameterNode;
59 import org.graalvm.compiler.nodes.PhiNode;
60 import org.graalvm.compiler.nodes.ProxyNode;
61 import org.graalvm.compiler.nodes.StateSplit;
62 import org.graalvm.compiler.nodes.StructuredGraph;
63 import org.graalvm.compiler.nodes.ValueNode;
64 import org.graalvm.compiler.nodes.ValuePhiNode;
65 import org.graalvm.compiler.nodes.calc.FloatingNode;
66 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
83
84 private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
85 private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
86
87 private final BytecodeParser parser;
88 private final GraphBuilderTool tool;
89 private final Bytecode code;
90 private int stackSize;
91 protected final ValueNode[] locals;
92 protected final ValueNode[] stack;
93 private ValueNode[] lockedObjects;
94 private boolean canVerifyKind;
95
96 /**
97 * @see BytecodeFrame#rethrowException
98 */
99 private boolean rethrowException;
100
101 private MonitorIdNode[] monitorIds;
102 private final StructuredGraph graph;
103 private final boolean clearNonLiveLocals;
104 private FrameState outerFrameState;
105
106 /**
107 * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more
108 * than one when the current block contains no side-effects but merging predecessor blocks do.
109 */
110 private List<StateSplit> sideEffects;
111
112 private JavaConstant constantReceiver;
113
114 /**
115 * Creates a new frame state builder for the given method and the given target graph.
116 *
117 * @param method the method whose frame is simulated
118 * @param graph the target graph of Graal nodes created by the builder
119 */
120 public FrameStateBuilder(GraphBuilderTool tool, ResolvedJavaMethod method, StructuredGraph graph) {
121 this(tool, new ResolvedJavaMethodBytecode(method), graph);
122 }
123
127 *
128 * @param code the bytecode in which the frame exists
129 * @param graph the target graph of Graal nodes created by the builder
130 */
131 public FrameStateBuilder(GraphBuilderTool tool, Bytecode code, StructuredGraph graph) {
132 this.tool = tool;
133 if (tool instanceof BytecodeParser) {
134 this.parser = (BytecodeParser) tool;
135 } else {
136 this.parser = null;
137 }
138 this.code = code;
139 this.locals = allocateArray(code.getMaxLocals());
140 this.stack = allocateArray(Math.max(1, code.getMaxStackSize()));
141 this.lockedObjects = allocateArray(0);
142
143 assert graph != null;
144
145 this.monitorIds = EMPTY_MONITOR_ARRAY;
146 this.graph = graph;
147 this.clearNonLiveLocals = GraalOptions.OptClearNonLiveLocals.getValue(graph.getOptions());
148 this.canVerifyKind = true;
149 }
150
151 public void disableKindVerification() {
152 canVerifyKind = false;
153 }
154
155 public void initializeFromArgumentsArray(ValueNode[] arguments) {
156
157 int javaIndex = 0;
158 int index = 0;
159 if (!getMethod().isStatic()) {
160 // set the receiver
161 locals[javaIndex] = arguments[index];
162 javaIndex = 1;
163 index = 1;
164 constantReceiver = locals[0].asJavaConstant();
165 }
166 Signature sig = getMethod().getSignature();
167 int max = sig.getParameterCount(false);
249 index++;
250 }
251 }
252
253 private FrameStateBuilder(FrameStateBuilder other) {
254 this.parser = other.parser;
255 this.tool = other.tool;
256 this.code = other.code;
257 this.stackSize = other.stackSize;
258 this.locals = other.locals.clone();
259 this.stack = other.stack.clone();
260 this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone();
261 this.rethrowException = other.rethrowException;
262 this.canVerifyKind = other.canVerifyKind;
263
264 assert locals.length == code.getMaxLocals();
265 assert stack.length == Math.max(1, code.getMaxStackSize());
266
267 assert other.graph != null;
268 graph = other.graph;
269 clearNonLiveLocals = other.clearNonLiveLocals;
270 monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone();
271
272 assert locals.length == code.getMaxLocals();
273 assert stack.length == Math.max(1, code.getMaxStackSize());
274 assert lockedObjects.length == monitorIds.length;
275 }
276
277 private static ValueNode[] allocateArray(int length) {
278 return length == 0 ? EMPTY_ARRAY : new ValueNode[length];
279 }
280
281 public ResolvedJavaMethod getMethod() {
282 return code.getMethod();
283 }
284
285 @Override
286 public String toString() {
287 StringBuilder sb = new StringBuilder();
288 sb.append("[locals: [");
289 for (int i = 0; i < locals.length; i++) {
334 if (pushedValues != null) {
335 assert pushedSlotKinds.length == pushedValues.length;
336 int stackSizeToRestore = stackSize;
337 for (int i = 0; i < pushedValues.length; i++) {
338 push(pushedSlotKinds[i], pushedValues[i]);
339 }
340 FrameState res = graph.add(new FrameState(outerFrameState, code, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
341 stackSize = stackSizeToRestore;
342 return res;
343 } else {
344 if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
345 assert outerFrameState == null;
346 clearLocals();
347 }
348 return graph.add(new FrameState(outerFrameState, code, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall));
349 }
350 }
351
352 public NodeSourcePosition createBytecodePosition(int bci) {
353 BytecodeParser parent = parser.getParent();
354 if (HideSubstitutionStates.getValue(parser.graph.getOptions())) {
355 if (parser.parsingIntrinsic()) {
356 // Attribute to the method being replaced
357 return new NodeSourcePosition(constantReceiver, parent.getFrameStateBuilder().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1);
358 }
359 // Skip intrinsic frames
360 parent = parser.getNonIntrinsicAncestor();
361 }
362 return create(null, constantReceiver, bci, parent);
363 }
364
365 private NodeSourcePosition create(NodeSourcePosition o, JavaConstant receiver, int bci, BytecodeParser parent) {
366 NodeSourcePosition outer = o;
367 if (outer == null && parent != null) {
368 outer = parent.getFrameStateBuilder().createBytecodePosition(parent.bci());
369 }
370 if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
371 return FrameState.toSourcePosition(outerFrameState);
372 }
373 if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
374 throw shouldNotReachHere();
611 if (stack[i] == value) {
612 return true;
613 }
614 }
615 assert lockedObjects.length == monitorIds.length;
616 for (int i = 0; i < lockedObjects.length; i++) {
617 if (lockedObjects[i] == value || monitorIds[i] == value) {
618 return true;
619 }
620 }
621 return false;
622 }
623
624 public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
625 /*
626 * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
627 * remove it for normal compilations, but not for OSR compilations - otherwise dead object
628 * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
629 * Kind.Illegal, because the conflicting branch might not have been parsed.
630 */
631 if (!clearNonLiveLocals) {
632 return;
633 }
634 if (liveIn) {
635 for (int i = 0; i < locals.length; i++) {
636 if (!liveness.localIsLiveIn(block, i)) {
637 assert locals[i] != TWO_SLOT_MARKER || locals[i - 1] == null : "Clearing of second slot must have cleared the first slot too";
638 locals[i] = null;
639 }
640 }
641 } else {
642 for (int i = 0; i < locals.length; i++) {
643 if (!liveness.localIsLiveOut(block, i)) {
644 assert locals[i] != TWO_SLOT_MARKER || locals[i - 1] == null : "Clearing of second slot must have cleared the first slot too";
645 locals[i] = null;
646 }
647 }
648 }
649 }
650
651 /**
|