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 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    }