IDEA-132625 (decompiler time limit)
[idea/community.git] / plugins / java-decompiler / engine / src / org / jetbrains / java / decompiler / main / rels / ClassWrapper.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.java.decompiler.main.rels;
17
18 import org.jetbrains.java.decompiler.code.CodeConstants;
19 import org.jetbrains.java.decompiler.main.DecompilerContext;
20 import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
21 import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
22 import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
23 import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
24 import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
25 import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
26 import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
27 import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
28 import org.jetbrains.java.decompiler.struct.StructClass;
29 import org.jetbrains.java.decompiler.struct.StructField;
30 import org.jetbrains.java.decompiler.struct.StructMethod;
31 import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
32 import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
33 import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
34 import org.jetbrains.java.decompiler.util.InterpreterUtil;
35 import org.jetbrains.java.decompiler.util.VBStyleCollection;
36
37 import java.io.IOException;
38 import java.util.HashSet;
39 import java.util.Set;
40
41 public class ClassWrapper {
42
43   private StructClass classStruct;
44   private Set<String> hiddenMembers = new HashSet<String>();
45   private VBStyleCollection<Exprent, String> staticFieldInitializers = new VBStyleCollection<Exprent, String>();
46   private VBStyleCollection<Exprent, String> dynamicFieldInitializers = new VBStyleCollection<Exprent, String>();
47   private VBStyleCollection<MethodWrapper, String> methods = new VBStyleCollection<MethodWrapper, String>();
48
49   public ClassWrapper(StructClass classStruct) {
50     this.classStruct = classStruct;
51   }
52
53   public void init() throws IOException {
54     DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS, classStruct);
55     DecompilerContext.getLogger().startClass(classStruct.qualifiedName);
56
57     // collect field names
58     Set<String> setFieldNames = new HashSet<String>();
59     for (StructField fd : classStruct.getFields()) {
60       setFieldNames.add(fd.getName());
61     }
62
63     int maxSec = Integer.parseInt(DecompilerContext.getProperty(IFernflowerPreferences.MAX_PROCESSING_METHOD).toString());
64
65     for (StructMethod mt : classStruct.getMethods()) {
66       DecompilerContext.getLogger().startMethod(mt.getName() + " " + mt.getDescriptor());
67
68       VarNamesCollector vc = new VarNamesCollector();
69       DecompilerContext.setVarNamesCollector(vc);
70
71       CounterContainer counter = new CounterContainer();
72       DecompilerContext.setCounterContainer(counter);
73
74       DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD, mt);
75       DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR, MethodDescriptor.parseDescriptor(mt.getDescriptor()));
76
77       VarProcessor varProc = new VarProcessor();
78       DecompilerContext.setProperty(DecompilerContext.CURRENT_VAR_PROCESSOR, varProc);
79
80       RootStatement root = null;
81
82       boolean isError = false;
83
84       try {
85         if (mt.containsCode()) {
86           if (maxSec == 0) {
87             root = MethodProcessorRunnable.codeToJava(mt, varProc);
88           }
89           else {
90             MethodProcessorRunnable mtProc = new MethodProcessorRunnable(mt, varProc, DecompilerContext.getCurrentContext());
91
92             Thread mtThread = new Thread(mtProc);
93             long stopAt = System.currentTimeMillis() + maxSec * 1000;
94
95             mtThread.start();
96
97             while (!mtProc.isFinished()) {
98               synchronized (mtProc.lock) {
99                 mtProc.lock.wait(100);
100               }
101
102               if (System.currentTimeMillis() >= stopAt) {
103                 String message = "Processing time limit exceeded for method " + mt.getName() + ", execution interrupted.";
104                 DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.ERROR);
105                 killThread(mtThread);
106                 isError = true;
107                 break;
108               }
109             }
110
111             if (!isError) {
112               root = mtProc.getResult();
113             }
114           }
115         }
116         else {
117           boolean thisVar = !mt.hasModifier(CodeConstants.ACC_STATIC);
118           MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
119
120           int paramCount = 0;
121           if (thisVar) {
122             varProc.getThisVars().put(new VarVersionPair(0, 0), classStruct.qualifiedName);
123             paramCount = 1;
124           }
125           paramCount += md.params.length;
126
127           int varIndex = 0;
128           for (int i = 0; i < paramCount; i++) {
129             varProc.setVarName(new VarVersionPair(varIndex, 0), vc.getFreeName(varIndex));
130
131             if (thisVar) {
132               if (i == 0) {
133                 varIndex++;
134               }
135               else {
136                 varIndex += md.params[i - 1].stackSize;
137               }
138             }
139             else {
140               varIndex += md.params[i].stackSize;
141             }
142           }
143         }
144       }
145       catch (Throwable ex) {
146         DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be decompiled.", ex);
147         isError = true;
148       }
149
150       MethodWrapper methodWrapper = new MethodWrapper(root, varProc, mt, counter);
151       methodWrapper.decompiledWithErrors = isError;
152
153       methods.addWithKey(methodWrapper, InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
154
155       // rename vars so that no one has the same name as a field
156       varProc.refreshVarNames(new VarNamesCollector(setFieldNames));
157
158       // if debug information present and should be used
159       if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) {
160         StructLocalVariableTableAttribute attr = (StructLocalVariableTableAttribute)mt.getAttributes().getWithKey(
161           StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE);
162
163         if (attr != null) {
164           varProc.setDebugVarNames(attr.getMapVarNames());
165         }
166       }
167
168       DecompilerContext.getLogger().endMethod();
169     }
170
171     DecompilerContext.getLogger().endClass();
172   }
173
174   @SuppressWarnings("deprecation")
175   private static void killThread(Thread thread) {
176     thread.stop();
177   }
178
179   public MethodWrapper getMethodWrapper(String name, String descriptor) {
180     return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
181   }
182
183   public StructClass getClassStruct() {
184     return classStruct;
185   }
186
187   public VBStyleCollection<MethodWrapper, String> getMethods() {
188     return methods;
189   }
190
191   public Set<String> getHiddenMembers() {
192     return hiddenMembers;
193   }
194
195   public VBStyleCollection<Exprent, String> getStaticFieldInitializers() {
196     return staticFieldInitializers;
197   }
198
199   public VBStyleCollection<Exprent, String> getDynamicFieldInitializers() {
200     return dynamicFieldInitializers;
201   }
202 }