001/*
002 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.nodes;
024
025import java.util.*;
026import java.util.concurrent.atomic.*;
027import java.util.function.*;
028
029import jdk.internal.jvmci.compiler.Compiler;
030import com.oracle.graal.debug.*;
031import jdk.internal.jvmci.meta.*;
032import jdk.internal.jvmci.meta.Assumptions.Assumption;
033
034import com.oracle.graal.compiler.common.type.*;
035import com.oracle.graal.graph.*;
036import com.oracle.graal.graph.spi.*;
037import com.oracle.graal.nodes.calc.*;
038import com.oracle.graal.nodes.java.*;
039import com.oracle.graal.nodes.util.*;
040
041/**
042 * A graph that contains at least one distinguished node : the {@link #start() start} node. This
043 * node is the start of the control flow of the graph.
044 */
045public class StructuredGraph extends Graph implements JavaMethodContext {
046
047    /**
048     * The different stages of the compilation of a {@link Graph} regarding the status of
049     * {@link GuardNode guards}, {@link DeoptimizingNode deoptimizations} and {@link FrameState
050     * framestates}. The stage of a graph progresses monotonously.
051     *
052     */
053    public static enum GuardsStage {
054        /**
055         * During this stage, there can be {@link FloatingNode floating} {@link DeoptimizingNode}
056         * such as {@link GuardNode GuardNodes}. New {@link DeoptimizingNode DeoptimizingNodes} can
057         * be introduced without constraints. {@link FrameState} nodes are associated with
058         * {@link StateSplit} nodes.
059         */
060        FLOATING_GUARDS,
061        /**
062         * During this stage, all {@link DeoptimizingNode DeoptimizingNodes} must be
063         * {@link FixedNode fixed} but new {@link DeoptimizingNode DeoptimizingNodes} can still be
064         * introduced. {@link FrameState} nodes are still associated with {@link StateSplit} nodes.
065         */
066        FIXED_DEOPTS,
067        /**
068         * During this stage, all {@link DeoptimizingNode DeoptimizingNodes} must be
069         * {@link FixedNode fixed}. New {@link DeoptimizingNode DeoptimizingNodes} can not be
070         * introduced any more. {@link FrameState} nodes are now associated with
071         * {@link DeoptimizingNode} nodes.
072         */
073        AFTER_FSA;
074
075        public boolean allowsFloatingGuards() {
076            return this == FLOATING_GUARDS;
077        }
078
079        public boolean areFrameStatesAtDeopts() {
080            return this == AFTER_FSA;
081        }
082
083        public boolean areFrameStatesAtSideEffects() {
084            return !this.areFrameStatesAtDeopts();
085        }
086
087        public boolean areDeoptsFixed() {
088            return this.ordinal() >= FIXED_DEOPTS.ordinal();
089        }
090    }
091
092    /**
093     * Constants denoting whether or not {@link Assumption}s can be made while processing a graph.
094     */
095    public enum AllowAssumptions {
096        YES,
097        NO;
098        public static AllowAssumptions from(boolean flag) {
099            return flag ? YES : NO;
100        }
101    }
102
103    public static final long INVALID_GRAPH_ID = -1;
104
105    private static final AtomicLong uniqueGraphIds = new AtomicLong();
106
107    private StartNode start;
108    private final ResolvedJavaMethod method;
109    private final long graphId;
110    private final int entryBCI;
111    private GuardsStage guardsStage = GuardsStage.FLOATING_GUARDS;
112    private boolean isAfterFloatingReadPhase = false;
113    private boolean hasValueProxies = true;
114
115    /**
116     * The assumptions made while constructing and transforming this graph.
117     */
118    private final Assumptions assumptions;
119
120    private final SpeculationLog speculationLog;
121
122    /**
123     * Records the methods that were inlined while constructing this graph along with how many times
124     * each method was inlined.
125     */
126    private Map<ResolvedJavaMethod, Integer> inlinedMethods = new HashMap<>();
127
128    private static enum UnsafeAccessState {
129        NO_ACCESS,
130        HAS_ACCESS,
131        DISABLED
132    }
133
134    private UnsafeAccessState hasUnsafeAccess = UnsafeAccessState.NO_ACCESS;
135
136    /**
137     * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
138     * start} node.
139     */
140    public StructuredGraph(AllowAssumptions allowAssumptions) {
141        this(null, null, allowAssumptions);
142    }
143
144    /**
145     * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
146     * start} node.
147     */
148    public StructuredGraph(String name, ResolvedJavaMethod method, AllowAssumptions allowAssumptions) {
149        this(name, method, uniqueGraphIds.incrementAndGet(), Compiler.INVOCATION_ENTRY_BCI, allowAssumptions, null);
150    }
151
152    public StructuredGraph(String name, ResolvedJavaMethod method, AllowAssumptions allowAssumptions, SpeculationLog speculationLog) {
153        this(name, method, uniqueGraphIds.incrementAndGet(), Compiler.INVOCATION_ENTRY_BCI, allowAssumptions, speculationLog);
154    }
155
156    public StructuredGraph(ResolvedJavaMethod method, AllowAssumptions allowAssumptions) {
157        this(null, method, uniqueGraphIds.incrementAndGet(), Compiler.INVOCATION_ENTRY_BCI, allowAssumptions, null);
158    }
159
160    public StructuredGraph(ResolvedJavaMethod method, AllowAssumptions allowAssumptions, SpeculationLog speculationLog) {
161        this(null, method, uniqueGraphIds.incrementAndGet(), Compiler.INVOCATION_ENTRY_BCI, allowAssumptions, speculationLog);
162    }
163
164    public StructuredGraph(ResolvedJavaMethod method, int entryBCI, AllowAssumptions allowAssumptions, SpeculationLog speculationLog) {
165        this(null, method, uniqueGraphIds.incrementAndGet(), entryBCI, allowAssumptions, speculationLog);
166    }
167
168    private StructuredGraph(String name, ResolvedJavaMethod method, long graphId, int entryBCI, AllowAssumptions allowAssumptions, SpeculationLog speculationLog) {
169        super(name);
170        this.setStart(add(new StartNode()));
171        this.method = method;
172        this.graphId = graphId;
173        this.entryBCI = entryBCI;
174        this.assumptions = allowAssumptions == AllowAssumptions.YES ? new Assumptions() : null;
175        this.speculationLog = speculationLog;
176    }
177
178    public Stamp getReturnStamp() {
179        Stamp returnStamp = null;
180        for (ReturnNode returnNode : getNodes(ReturnNode.TYPE)) {
181            ValueNode result = returnNode.result();
182            if (result != null) {
183                if (returnStamp == null) {
184                    returnStamp = result.stamp();
185                } else {
186                    returnStamp = returnStamp.meet(result.stamp());
187                }
188            }
189        }
190        return returnStamp;
191    }
192
193    @Override
194    public String toString() {
195        StringBuilder buf = new StringBuilder(getClass().getSimpleName() + ":" + graphId);
196        String sep = "{";
197        if (name != null) {
198            buf.append(sep);
199            buf.append(name);
200            sep = ", ";
201        }
202        if (method != null) {
203            buf.append(sep);
204            buf.append(method);
205            sep = ", ";
206        }
207
208        if (!sep.equals("{")) {
209            buf.append("}");
210        }
211        return buf.toString();
212    }
213
214    public StartNode start() {
215        return start;
216    }
217
218    /**
219     * Gets the method from which this graph was built.
220     *
221     * @return null if this method was not built from a method or the method is not available
222     */
223    public ResolvedJavaMethod method() {
224        return method;
225    }
226
227    public int getEntryBCI() {
228        return entryBCI;
229    }
230
231    public boolean isOSR() {
232        return entryBCI != Compiler.INVOCATION_ENTRY_BCI;
233    }
234
235    public long graphId() {
236        return graphId;
237    }
238
239    public void setStart(StartNode start) {
240        this.start = start;
241    }
242
243    /**
244     * Creates a copy of this graph.
245     *
246     * @param newName the name of the copy, used for debugging purposes (can be null)
247     * @param duplicationMapCallback consumer of the duplication map created during the copying
248     */
249    @Override
250    protected Graph copy(String newName, Consumer<Map<Node, Node>> duplicationMapCallback) {
251        AllowAssumptions allowAssumptions = AllowAssumptions.from(assumptions != null);
252        boolean enableInlinedMethodRecording = isInlinedMethodRecordingEnabled();
253        StructuredGraph copy = new StructuredGraph(newName, method, graphId, entryBCI, allowAssumptions, speculationLog);
254        if (allowAssumptions == AllowAssumptions.YES && assumptions != null) {
255            copy.assumptions.record(assumptions);
256        }
257        if (!enableInlinedMethodRecording) {
258            copy.disableInlinedMethodRecording();
259        }
260        copy.hasUnsafeAccess = hasUnsafeAccess;
261        copy.setGuardsStage(getGuardsStage());
262        copy.isAfterFloatingReadPhase = isAfterFloatingReadPhase;
263        copy.hasValueProxies = hasValueProxies;
264        Map<Node, Node> replacements = Node.newMap();
265        replacements.put(start, copy.start);
266        Map<Node, Node> duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), replacements);
267        if (duplicationMapCallback != null) {
268            duplicationMapCallback.accept(duplicates);
269        }
270        return copy;
271    }
272
273    public ParameterNode getParameter(int index) {
274        for (ParameterNode param : getNodes(ParameterNode.TYPE)) {
275            if (param.index() == index) {
276                return param;
277            }
278        }
279        return null;
280    }
281
282    public Iterable<Invoke> getInvokes() {
283        final Iterator<MethodCallTargetNode> callTargets = getNodes(MethodCallTargetNode.TYPE).iterator();
284        return new Iterable<Invoke>() {
285
286            private Invoke next;
287
288            @Override
289            public Iterator<Invoke> iterator() {
290                return new Iterator<Invoke>() {
291
292                    @Override
293                    public boolean hasNext() {
294                        if (next == null) {
295                            while (callTargets.hasNext()) {
296                                Invoke i = callTargets.next().invoke();
297                                if (i != null) {
298                                    next = i;
299                                    return true;
300                                }
301                            }
302                            return false;
303                        } else {
304                            return true;
305                        }
306                    }
307
308                    @Override
309                    public Invoke next() {
310                        try {
311                            return next;
312                        } finally {
313                            next = null;
314                        }
315                    }
316
317                    @Override
318                    public void remove() {
319                        throw new UnsupportedOperationException();
320                    }
321                };
322            }
323        };
324    }
325
326    public boolean hasLoops() {
327        return hasNode(LoopBeginNode.TYPE);
328    }
329
330    public void removeFloating(FloatingNode node) {
331        assert node != null && node.isAlive() : "cannot remove " + node;
332        node.safeDelete();
333    }
334
335    public void replaceFloating(FloatingNode node, Node replacement) {
336        assert node != null && node.isAlive() && (replacement == null || replacement.isAlive()) : "cannot replace " + node + " with " + replacement;
337        node.replaceAtUsages(replacement);
338        node.safeDelete();
339    }
340
341    /**
342     * Unlinks a node from all its control flow neighbors and then removes it from its graph. The
343     * node must have no {@linkplain Node#usages() usages}.
344     *
345     * @param node the node to be unlinked and removed
346     */
347    public void removeFixed(FixedWithNextNode node) {
348        assert node != null;
349        if (node instanceof AbstractBeginNode) {
350            ((AbstractBeginNode) node).prepareDelete();
351        }
352        assert node.hasNoUsages() : node + " " + node.usages().count() + ", " + node.usages().first();
353        GraphUtil.unlinkFixedNode(node);
354        node.safeDelete();
355    }
356
357    public void replaceFixed(FixedWithNextNode node, Node replacement) {
358        if (replacement instanceof FixedWithNextNode) {
359            replaceFixedWithFixed(node, (FixedWithNextNode) replacement);
360        } else {
361            assert replacement != null : "cannot replace " + node + " with null";
362            assert replacement instanceof FloatingNode : "cannot replace " + node + " with " + replacement;
363            replaceFixedWithFloating(node, (FloatingNode) replacement);
364        }
365    }
366
367    public void replaceFixedWithFixed(FixedWithNextNode node, FixedWithNextNode replacement) {
368        assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
369        FixedNode next = node.next();
370        node.setNext(null);
371        replacement.setNext(next);
372        node.replaceAndDelete(replacement);
373        if (node == start) {
374            setStart((StartNode) replacement);
375        }
376    }
377
378    public void replaceFixedWithFloating(FixedWithNextNode node, FloatingNode replacement) {
379        assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
380        GraphUtil.unlinkFixedNode(node);
381        node.replaceAtUsages(replacement);
382        node.safeDelete();
383    }
384
385    public void removeSplit(ControlSplitNode node, AbstractBeginNode survivingSuccessor) {
386        assert node != null;
387        assert node.hasNoUsages();
388        assert survivingSuccessor != null;
389        node.clearSuccessors();
390        node.replaceAtPredecessor(survivingSuccessor);
391        node.safeDelete();
392    }
393
394    public void removeSplitPropagate(ControlSplitNode node, AbstractBeginNode survivingSuccessor) {
395        removeSplitPropagate(node, survivingSuccessor, null);
396    }
397
398    public void removeSplitPropagate(ControlSplitNode node, AbstractBeginNode survivingSuccessor, SimplifierTool tool) {
399        assert node != null;
400        assert node.hasNoUsages();
401        assert survivingSuccessor != null;
402        List<Node> snapshot = node.successors().snapshot();
403        node.clearSuccessors();
404        node.replaceAtPredecessor(survivingSuccessor);
405        node.safeDelete();
406        for (Node successor : snapshot) {
407            if (successor != null && successor.isAlive()) {
408                if (successor != survivingSuccessor) {
409                    GraphUtil.killCFG(successor, tool);
410                }
411            }
412        }
413    }
414
415    public void replaceSplit(ControlSplitNode node, Node replacement, AbstractBeginNode survivingSuccessor) {
416        if (replacement instanceof FixedWithNextNode) {
417            replaceSplitWithFixed(node, (FixedWithNextNode) replacement, survivingSuccessor);
418        } else {
419            assert replacement != null : "cannot replace " + node + " with null";
420            assert replacement instanceof FloatingNode : "cannot replace " + node + " with " + replacement;
421            replaceSplitWithFloating(node, (FloatingNode) replacement, survivingSuccessor);
422        }
423    }
424
425    public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, AbstractBeginNode survivingSuccessor) {
426        assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
427        assert survivingSuccessor != null;
428        node.clearSuccessors();
429        replacement.setNext(survivingSuccessor);
430        node.replaceAndDelete(replacement);
431    }
432
433    public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, AbstractBeginNode survivingSuccessor) {
434        assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
435        assert survivingSuccessor != null;
436        node.clearSuccessors();
437        node.replaceAtPredecessor(survivingSuccessor);
438        node.replaceAtUsages(replacement);
439        node.safeDelete();
440    }
441
442    public void addAfterFixed(FixedWithNextNode node, FixedNode newNode) {
443        assert node != null && newNode != null && node.isAlive() && newNode.isAlive() : "cannot add " + newNode + " after " + node;
444        FixedNode next = node.next();
445        node.setNext(newNode);
446        if (next != null) {
447            assert newNode instanceof FixedWithNextNode;
448            FixedWithNextNode newFixedWithNext = (FixedWithNextNode) newNode;
449            assert newFixedWithNext.next() == null;
450            newFixedWithNext.setNext(next);
451        }
452    }
453
454    public void addBeforeFixed(FixedNode node, FixedWithNextNode newNode) {
455        assert node != null && newNode != null && node.isAlive() && newNode.isAlive() : "cannot add " + newNode + " before " + node;
456        assert node.predecessor() != null && node.predecessor() instanceof FixedWithNextNode : "cannot add " + newNode + " before " + node;
457        assert newNode.next() == null : newNode;
458        assert !(node instanceof AbstractMergeNode);
459        FixedWithNextNode pred = (FixedWithNextNode) node.predecessor();
460        pred.setNext(newNode);
461        newNode.setNext(node);
462    }
463
464    public void reduceDegenerateLoopBegin(LoopBeginNode begin) {
465        assert begin.loopEnds().isEmpty() : "Loop begin still has backedges";
466        if (begin.forwardEndCount() == 1) { // bypass merge and remove
467            reduceTrivialMerge(begin);
468        } else { // convert to merge
469            AbstractMergeNode merge = this.add(new MergeNode());
470            this.replaceFixedWithFixed(begin, merge);
471        }
472    }
473
474    public void reduceTrivialMerge(AbstractMergeNode merge) {
475        assert merge.forwardEndCount() == 1;
476        assert !(merge instanceof LoopBeginNode) || ((LoopBeginNode) merge).loopEnds().isEmpty();
477        for (PhiNode phi : merge.phis().snapshot()) {
478            assert phi.valueCount() == 1;
479            ValueNode singleValue = phi.valueAt(0);
480            phi.replaceAtUsages(singleValue);
481            phi.safeDelete();
482        }
483        // remove loop exits
484        if (merge instanceof LoopBeginNode) {
485            ((LoopBeginNode) merge).removeExits();
486        }
487        AbstractEndNode singleEnd = merge.forwardEndAt(0);
488        FixedNode sux = merge.next();
489        FrameState stateAfter = merge.stateAfter();
490        // evacuateGuards
491        merge.prepareDelete((FixedNode) singleEnd.predecessor());
492        merge.safeDelete();
493        if (stateAfter != null && stateAfter.isAlive() && stateAfter.hasNoUsages()) {
494            GraphUtil.killWithUnusedFloatingInputs(stateAfter);
495        }
496        if (sux == null) {
497            singleEnd.replaceAtPredecessor(null);
498            singleEnd.safeDelete();
499        } else {
500            singleEnd.replaceAndDelete(sux);
501        }
502    }
503
504    public GuardsStage getGuardsStage() {
505        return guardsStage;
506    }
507
508    public void setGuardsStage(GuardsStage guardsStage) {
509        assert guardsStage.ordinal() >= this.guardsStage.ordinal();
510        this.guardsStage = guardsStage;
511    }
512
513    public boolean isAfterFloatingReadPhase() {
514        return isAfterFloatingReadPhase;
515    }
516
517    public void setAfterFloatingReadPhase(boolean state) {
518        assert state : "cannot 'unapply' floating read phase on graph";
519        isAfterFloatingReadPhase = state;
520    }
521
522    public boolean hasValueProxies() {
523        return hasValueProxies;
524    }
525
526    public void setHasValueProxies(boolean state) {
527        assert !state : "cannot 'unapply' value proxy removal on graph";
528        hasValueProxies = state;
529    }
530
531    /**
532     * Gets the object for recording assumptions while constructing of this graph.
533     *
534     * @return {@code null} if assumptions cannot be made for this graph
535     */
536    public Assumptions getAssumptions() {
537        return assumptions;
538    }
539
540    /**
541     * Disables method inlining recording while constructing this graph. This can be done at most
542     * once and must be done before any inlined methods are recorded.
543     */
544    public void disableInlinedMethodRecording() {
545        assert inlinedMethods != null : "cannot disable method inlining recording more than once";
546        assert inlinedMethods.isEmpty() : "cannot disable method inlining recording once methods have been recorded";
547        inlinedMethods = null;
548    }
549
550    public boolean isInlinedMethodRecordingEnabled() {
551        return inlinedMethods != null;
552    }
553
554    /**
555     * Gets the methods that were inlined while constructing this graph.
556     *
557     * @return {@code null} if method inlining recording has been
558     *         {@linkplain #disableInlinedMethodRecording() disabled}
559     */
560    public Set<ResolvedJavaMethod> getInlinedMethods() {
561        return inlinedMethods == null ? null : inlinedMethods.keySet();
562    }
563
564    /**
565     * If method inlining recording has not been {@linkplain #disableInlinedMethodRecording()
566     * disabled}, records that {@code inlinedMethod} was inlined to this graph. Otherwise, this
567     * method does nothing.
568     */
569    public void recordInlinedMethod(ResolvedJavaMethod inlinedMethod) {
570        if (inlinedMethods != null) {
571            Integer count = inlinedMethods.get(inlinedMethod);
572            if (count != null) {
573                inlinedMethods.put(inlinedMethod, count + 1);
574            } else {
575                inlinedMethods.put(inlinedMethod, 1);
576            }
577        }
578    }
579
580    /**
581     * If method inlining recording has not been {@linkplain #disableInlinedMethodRecording()
582     * disabled}, updates the {@linkplain #getInlinedMethods() inlined methods} of this graph with
583     * the inlined methods of another graph. Otherwise, this method does nothing.
584     */
585    public void updateInlinedMethods(StructuredGraph other) {
586        if (inlinedMethods != null) {
587            assert this != other;
588            Map<ResolvedJavaMethod, Integer> otherInlinedMethods = other.inlinedMethods;
589            if (otherInlinedMethods != null) {
590                for (Map.Entry<ResolvedJavaMethod, Integer> e : otherInlinedMethods.entrySet()) {
591                    ResolvedJavaMethod key = e.getKey();
592                    Integer count = inlinedMethods.get(key);
593                    if (count != null) {
594                        inlinedMethods.put(key, count + e.getValue());
595                    } else {
596                        inlinedMethods.put(key, e.getValue());
597                    }
598                }
599            }
600        }
601    }
602
603    /**
604     * Gets the input bytecode {@linkplain ResolvedJavaMethod#getCodeSize() size} from which this
605     * graph is constructed. This ignores how many bytecodes in each constituent method are actually
606     * parsed (which may be none for methods whose IR is retrieved from a cache or less than the
607     * full amount for any given method due to profile guided branch pruning). If method inlining
608     * recording has been {@linkplain #disableInlinedMethodRecording() disabled} for this graph,
609     * bytecode counts for inlined methods are not included in the returned value.
610     */
611    public int getBytecodeSize() {
612        int res = method.getCodeSize();
613        if (inlinedMethods != null) {
614            for (Map.Entry<ResolvedJavaMethod, Integer> e : inlinedMethods.entrySet()) {
615                int inlinedBytes = e.getValue() * e.getKey().getCodeSize();
616                res += inlinedBytes;
617            }
618        }
619        return res;
620    }
621
622    /**
623     *
624     * @return true if the graph contains only a {@link StartNode} and {@link ReturnNode}
625     */
626    public boolean isTrivial() {
627        return !(start.next() instanceof ReturnNode);
628    }
629
630    public JavaMethod asJavaMethod() {
631        return method();
632    }
633
634    public boolean hasUnsafeAccess() {
635        return hasUnsafeAccess == UnsafeAccessState.HAS_ACCESS;
636    }
637
638    public void markUnsafeAccess() {
639        if (hasUnsafeAccess == UnsafeAccessState.DISABLED) {
640            return;
641        }
642        hasUnsafeAccess = UnsafeAccessState.HAS_ACCESS;
643    }
644
645    public void disableUnsafeAccessTracking() {
646        hasUnsafeAccess = UnsafeAccessState.DISABLED;
647    }
648
649    public boolean isUnsafeAccessTrackingEnabled() {
650        return hasUnsafeAccess != UnsafeAccessState.DISABLED;
651    }
652
653    public SpeculationLog getSpeculationLog() {
654        return speculationLog;
655    }
656}