1/*
2 * Copyright (c) 2014, 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.lir.framemap;
24
25import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
26
27import java.util.ArrayList;
28import java.util.BitSet;
29import java.util.EnumSet;
30import java.util.List;
31
32import org.graalvm.compiler.core.common.LIRKind;
33import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
34import org.graalvm.compiler.debug.DebugContext;
35import org.graalvm.compiler.debug.GraalError;
36import org.graalvm.compiler.lir.InstructionValueConsumer;
37import org.graalvm.compiler.lir.LIR;
38import org.graalvm.compiler.lir.LIRInstruction;
39import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
40import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
41import org.graalvm.compiler.lir.VirtualStackSlot;
42import org.graalvm.compiler.lir.gen.LIRGenerationResult;
43
44import jdk.vm.ci.code.CallingConvention;
45import jdk.vm.ci.code.CodeCacheProvider;
46import jdk.vm.ci.code.RegisterConfig;
47import jdk.vm.ci.meta.JavaKind;
48import jdk.vm.ci.meta.Value;
49import jdk.vm.ci.meta.ValueKind;
50
51/**
52 * A FrameMapBuilder that records allocation.
53 */
54public class FrameMapBuilderImpl extends FrameMapBuilderTool {
55
56    private final RegisterConfig registerConfig;
57    private final CodeCacheProvider codeCache;
58    private final FrameMap frameMap;
59    private final List<VirtualStackSlot> stackSlots;
60    private final List<CallingConvention> calls;
61    private int numStackSlots;
62
63    public FrameMapBuilderImpl(FrameMap frameMap, CodeCacheProvider codeCache, RegisterConfig registerConfig) {
64        assert registerConfig != null : "No register config!";
65        this.registerConfig = registerConfig == null ? codeCache.getRegisterConfig() : registerConfig;
66        this.codeCache = codeCache;
67        this.frameMap = frameMap;
68        this.stackSlots = new ArrayList<>();
69        this.calls = new ArrayList<>();
70        this.numStackSlots = 0;
71    }
72
73    @Override
74    public VirtualStackSlot allocateSpillSlot(ValueKind<?> kind) {
75        SimpleVirtualStackSlot slot = new SimpleVirtualStackSlot(numStackSlots++, kind);
76        stackSlots.add(slot);
77        return slot;
78    }
79
80    @Override
81    public VirtualStackSlot allocateStackSlots(int slots, BitSet objects, List<VirtualStackSlot> outObjectStackSlots) {
82        if (slots == 0) {
83            return null;
84        }
85        if (outObjectStackSlots != null) {
86            throw GraalError.unimplemented();
87        }
88        VirtualStackSlotRange slot = new VirtualStackSlotRange(numStackSlots++, slots, objects, LIRKind.fromJavaKind(frameMap.getTarget().arch, JavaKind.Object));
89        stackSlots.add(slot);
90        return slot;
91    }
92
93    @Override
94    public RegisterConfig getRegisterConfig() {
95        return registerConfig;
96    }
97
98    @Override
99    public CodeCacheProvider getCodeCache() {
100        return codeCache;
101    }
102
103    @Override
104    public FrameMap getFrameMap() {
105        return frameMap;
106    }
107
108    @Override
109    public int getNumberOfStackSlots() {
110        return numStackSlots;
111    }
112
113    @Override
114    public void callsMethod(CallingConvention cc) {
115        calls.add(cc);
116    }
117
118    @Override
119    @SuppressWarnings("try")
120    public FrameMap buildFrameMap(LIRGenerationResult res) {
121        DebugContext debug = res.getLIR().getDebug();
122        if (debug.areScopesEnabled()) {
123            verifyStackSlotAllocation(res);
124        }
125        for (CallingConvention cc : calls) {
126            frameMap.callsMethod(cc);
127        }
128        frameMap.finish();
129        return frameMap;
130    }
131
132    private static void verifyStackSlotAllocation(LIRGenerationResult res) {
133        LIR lir = res.getLIR();
134        InstructionValueConsumer verifySlots = (LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) -> {
135            assert !isVirtualStackSlot(value) : String.format("Instruction %s contains a virtual stack slot %s", op, value);
136        };
137        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
138            lir.getLIRforBlock(block).forEach(op -> {
139                op.visitEachInput(verifySlots);
140                op.visitEachAlive(verifySlots);
141                op.visitEachState(verifySlots);
142
143                op.visitEachTemp(verifySlots);
144                op.visitEachOutput(verifySlots);
145            });
146        }
147    }
148
149    @Override
150    public List<VirtualStackSlot> getStackSlots() {
151        return stackSlots;
152    }
153
154}
155