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    
017    package org.jetbrains.jet.codegen;
018    
019    import com.google.common.collect.Lists;
020    import com.intellij.openapi.util.Trinity;
021    import gnu.trove.TObjectIntHashMap;
022    import gnu.trove.TObjectIntIterator;
023    import org.jetbrains.asm4.Type;
024    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
025    
026    import java.util.ArrayList;
027    import java.util.Collections;
028    import java.util.Comparator;
029    import java.util.List;
030    
031    public 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 int getCurrentSize() {
074            return myMaxIndex;
075        }
076    
077        public class Mark {
078            private final int myIndex;
079    
080            public Mark(int index) {
081                myIndex = index;
082            }
083    
084            public void dropTo() {
085                List<DeclarationDescriptor> descriptorsToDrop = new ArrayList<DeclarationDescriptor>();
086                TObjectIntIterator<DeclarationDescriptor> iterator = myVarIndex.iterator();
087                while (iterator.hasNext()) {
088                    iterator.advance();
089                    if (iterator.value() >= myIndex) {
090                        descriptorsToDrop.add(iterator.key());
091                    }
092                }
093                for (DeclarationDescriptor declarationDescriptor : descriptorsToDrop) {
094                    myVarIndex.remove(declarationDescriptor);
095                    myVarSizes.remove(declarationDescriptor);
096                }
097                myMaxIndex = myIndex;
098            }
099        }
100    
101        @Override
102        public String toString() {
103            StringBuilder sb = new StringBuilder();
104    
105            if (myVarIndex.size() != myVarSizes.size()) {
106                return "inconsistent";
107            }
108    
109            List<Trinity<DeclarationDescriptor, Integer, Integer>> descriptors = Lists.newArrayList();
110    
111            for (Object descriptor0 : myVarIndex.keys()) {
112                DeclarationDescriptor descriptor = (DeclarationDescriptor) descriptor0;
113                int varIndex = myVarIndex.get(descriptor);
114                int varSize = myVarSizes.get(descriptor);
115                descriptors.add(Trinity.create(descriptor, varIndex, varSize));
116            }
117    
118            Collections.sort(descriptors, new Comparator<Trinity<DeclarationDescriptor, Integer, Integer>>() {
119                @Override
120                public int compare(
121                        Trinity<DeclarationDescriptor, Integer, Integer> left,
122                        Trinity<DeclarationDescriptor, Integer, Integer> right
123                ) {
124                    return left.second - right.second;
125                }
126            });
127    
128            sb.append("size=").append(myMaxIndex);
129    
130            boolean first = true;
131            for (Trinity<DeclarationDescriptor, Integer, Integer> t : descriptors) {
132                if (!first) {
133                    sb.append(", ");
134                }
135                first = false;
136                sb.append(t.first).append(",i=").append(t.second).append(",s=").append(t.third);
137            }
138    
139            return sb.toString();
140        }
141    }