001/*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.jetbrains.jet.codegen;
018
019import com.google.common.collect.Lists;
020import com.intellij.openapi.util.Trinity;
021import gnu.trove.TObjectIntHashMap;
022import gnu.trove.TObjectIntIterator;
023import org.jetbrains.asm4.Type;
024import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
025
026import java.util.ArrayList;
027import java.util.Collections;
028import java.util.Comparator;
029import java.util.List;
030
031public class FrameMap {
032    private final TObjectIntHashMap<DeclarationDescriptor> myVarIndex = new TObjectIntHashMap<DeclarationDescriptor>();
033    private final TObjectIntHashMap<DeclarationDescriptor> myVarSizes = new TObjectIntHashMap<DeclarationDescriptor>();
034    private int myMaxIndex = 0;
035
036    public int enter(DeclarationDescriptor descriptor, Type type) {
037        int index = myMaxIndex;
038        myVarIndex.put(descriptor, index);
039        myMaxIndex += type.getSize();
040        myVarSizes.put(descriptor, type.getSize());
041        return index;
042    }
043
044    public int leave(DeclarationDescriptor descriptor) {
045        int size = myVarSizes.get(descriptor);
046        myMaxIndex -= size;
047        myVarSizes.remove(descriptor);
048        int oldIndex = myVarIndex.remove(descriptor);
049        if (oldIndex != myMaxIndex) {
050            throw new IllegalStateException("descriptor can be left only if it is last");
051        }
052        return oldIndex;
053    }
054
055    public int enterTemp(Type type) {
056        int result = myMaxIndex;
057        myMaxIndex += type.getSize();
058        return result;
059    }
060
061    public void leaveTemp(Type type) {
062        myMaxIndex -= type.getSize();
063    }
064
065    public int getIndex(DeclarationDescriptor descriptor) {
066        return myVarIndex.contains(descriptor) ? myVarIndex.get(descriptor) : -1;
067    }
068
069    public Mark mark() {
070        return new Mark(myMaxIndex);
071    }
072
073    public class Mark {
074        private final int myIndex;
075
076        public Mark(int index) {
077            myIndex = index;
078        }
079
080        public void dropTo() {
081            List<DeclarationDescriptor> descriptorsToDrop = new ArrayList<DeclarationDescriptor>();
082            TObjectIntIterator<DeclarationDescriptor> iterator = myVarIndex.iterator();
083            while (iterator.hasNext()) {
084                iterator.advance();
085                if (iterator.value() >= myIndex) {
086                    descriptorsToDrop.add(iterator.key());
087                }
088            }
089            for (DeclarationDescriptor declarationDescriptor : descriptorsToDrop) {
090                myVarIndex.remove(declarationDescriptor);
091                myVarSizes.remove(declarationDescriptor);
092            }
093            myMaxIndex = myIndex;
094        }
095    }
096
097    @Override
098    public String toString() {
099        StringBuilder sb = new StringBuilder();
100
101        if (myVarIndex.size() != myVarSizes.size()) {
102            return "inconsistent";
103        }
104
105        List<Trinity<DeclarationDescriptor, Integer, Integer>> descriptors = Lists.newArrayList();
106
107        for (Object descriptor0 : myVarIndex.keys()) {
108            DeclarationDescriptor descriptor = (DeclarationDescriptor) descriptor0;
109            int varIndex = myVarIndex.get(descriptor);
110            int varSize = myVarSizes.get(descriptor);
111            descriptors.add(Trinity.create(descriptor, varIndex, varSize));
112        }
113
114        Collections.sort(descriptors, new Comparator<Trinity<DeclarationDescriptor, Integer, Integer>>() {
115            @Override
116            public int compare(
117                    Trinity<DeclarationDescriptor, Integer, Integer> left,
118                    Trinity<DeclarationDescriptor, Integer, Integer> right
119            ) {
120                return left.second - right.second;
121            }
122        });
123
124        sb.append("size=").append(myMaxIndex);
125
126        boolean first = true;
127        for (Trinity<DeclarationDescriptor, Integer, Integer> t : descriptors) {
128            if (!first) {
129                sb.append(", ");
130            }
131            first = false;
132            sb.append(t.first).append(",i=").append(t.second).append(",s=").append(t.third);
133        }
134
135        return sb.toString();
136    }
137}