diff options
Diffstat (limited to 'src/org/jetbrains/java/decompiler/modules/decompiler/stats')
11 files changed, 2638 insertions, 2625 deletions
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java index 5cfa634..ddac0c5 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java @@ -1,17 +1,18 @@ /* - * Fernflower - The Analytical Java Decompiler - * http://www.reversed-java.com + * Copyright 2000-2014 JetBrains s.r.o. * - * (C) 2008 - 2010, Stiver + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This software is NEITHER public domain NOR free software - * as per GNU License. See license.txt for more details. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This software is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.jetbrains.java.decompiler.modules.decompiler.stats; import org.jetbrains.java.decompiler.code.CodeConstants; @@ -23,73 +24,73 @@ import org.jetbrains.java.decompiler.main.collectors.CounterContainer; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; public class BasicBlockStatement extends Statement { - - // ***************************************************************************** - // private fields - // ***************************************************************************** - - private BasicBlock block; - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - public BasicBlockStatement(BasicBlock block) { - - type = Statement.TYPE_BASICBLOCK; - - this.block = block; - - id = block.id; - CounterContainer coun = DecompilerContext.getCountercontainer(); - if(id>=coun.getCounter(CounterContainer.STATEMENT_COUNTER)) { - coun.setCounter(CounterContainer.STATEMENT_COUNTER, id+1); - } - - Instruction instr = block.getLastInstruction(); - if(instr != null) { - if(instr.group==CodeConstants.GROUP_JUMP && instr.opcode != CodeConstants.opc_goto) { - lastBasicType = LASTBASICTYPE_IF; - } else if(instr.group==CodeConstants.GROUP_SWITCH) { - lastBasicType = LASTBASICTYPE_SWITCH; - } - } - - // monitorenter and monitorexits - buildMonitorFlags(); - } - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public String toJava(int indent) { - return ExprProcessor.listToJava(varDefinitions, indent)+ - ExprProcessor.listToJava(exprents, indent); - } - - public Statement getSimpleCopy() { - - BasicBlock newblock = new BasicBlock( - DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)); - - SimpleInstructionSequence seq = new SimpleInstructionSequence(); - for(int i=0;i<block.getSeq().length();i++) { - seq.addInstruction(block.getSeq().getInstr(i).clone(), -1); - } - - newblock.setSeq(seq); - - return new BasicBlockStatement(newblock); - } - - - // ***************************************************************************** - // getter and setter methods - // ***************************************************************************** - - public BasicBlock getBlock() { - return block; - } - + + // ***************************************************************************** + // private fields + // ***************************************************************************** + + private BasicBlock block; + + // ***************************************************************************** + // constructors + // ***************************************************************************** + + public BasicBlockStatement(BasicBlock block) { + + type = Statement.TYPE_BASICBLOCK; + + this.block = block; + + id = block.id; + CounterContainer coun = DecompilerContext.getCountercontainer(); + if (id >= coun.getCounter(CounterContainer.STATEMENT_COUNTER)) { + coun.setCounter(CounterContainer.STATEMENT_COUNTER, id + 1); + } + + Instruction instr = block.getLastInstruction(); + if (instr != null) { + if (instr.group == CodeConstants.GROUP_JUMP && instr.opcode != CodeConstants.opc_goto) { + lastBasicType = LASTBASICTYPE_IF; + } + else if (instr.group == CodeConstants.GROUP_SWITCH) { + lastBasicType = LASTBASICTYPE_SWITCH; + } + } + + // monitorenter and monitorexits + buildMonitorFlags(); + } + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public String toJava(int indent) { + return ExprProcessor.listToJava(varDefinitions, indent) + + ExprProcessor.listToJava(exprents, indent); + } + + public Statement getSimpleCopy() { + + BasicBlock newblock = new BasicBlock( + DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)); + + SimpleInstructionSequence seq = new SimpleInstructionSequence(); + for (int i = 0; i < block.getSeq().length(); i++) { + seq.addInstruction(block.getSeq().getInstr(i).clone(), -1); + } + + newblock.setSeq(seq); + + return new BasicBlockStatement(newblock); + } + + + // ***************************************************************************** + // getter and setter methods + // ***************************************************************************** + + public BasicBlock getBlock() { + return block; + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java index 25adb29..9f1a3f5 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java @@ -1,24 +1,20 @@ /* - * Fernflower - The Analytical Java Decompiler - * http://www.reversed-java.com + * Copyright 2000-2014 JetBrains s.r.o. * - * (C) 2008 - 2010, Stiver + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This software is NEITHER public domain NOR free software - * as per GNU License. See license.txt for more details. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This software is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.jetbrains.java.decompiler.modules.decompiler.stats; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; - import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.collectors.CounterContainer; @@ -30,204 +26,210 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; import org.jetbrains.java.decompiler.struct.gen.VarType; import org.jetbrains.java.decompiler.util.InterpreterUtil; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + public class CatchAllStatement extends Statement { - - private Statement handler; - - private boolean isFinally; - - private VarExprent monitor; - - private List<VarExprent> vars = new ArrayList<VarExprent>(); - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - private CatchAllStatement(){ - type = Statement.TYPE_CATCHALL; - }; - - private CatchAllStatement(Statement head, Statement handler) { - - this(); - - first = head; - stats.addWithKey(head, head.id); - - this.handler = handler; - stats.addWithKey(handler, handler.id); - - List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL); - if(!lstSuccs.isEmpty()) { - StatEdge edge = lstSuccs.get(0); - if(edge.getType() == StatEdge.TYPE_REGULAR) { - post = edge.getDestination(); - } - } - - vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER), - new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Throwable"), - (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR))); - - } - - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public static Statement isHead(Statement head) { - - if(head.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) { - return null; - } - - HashSet<Statement> setHandlers = DecHelper.getUniquePredExceptions(head); - - if(setHandlers.size() != 1) { - return null; - } - - for(StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) { - Statement exc = edge.getDestination(); - - if(edge.getExceptions() == null && setHandlers.contains(exc) && exc.getLastBasicType() == LASTBASICTYPE_GENERAL) { - List<StatEdge> lstSuccs = exc.getSuccessorEdges(STATEDGE_DIRECT_ALL); - if(lstSuccs.isEmpty() || lstSuccs.get(0).getType() != StatEdge.TYPE_REGULAR) { - - if(head.isMonitorEnter() || exc.isMonitorEnter()) { - return null; - } - - if(DecHelper.checkStatementExceptions(Arrays.asList(new Statement[] {head, exc}))) { - return new CatchAllStatement(head, exc); - } - } - } - } - - return null; - } - - public String toJava(int indent) { - String indstr = InterpreterUtil.getIndentString(indent); - String indstr1 = null; - - String new_line_separator = DecompilerContext.getNewLineSeparator(); - - StringBuffer buf = new StringBuffer(); - - buf.append(ExprProcessor.listToJava(varDefinitions, indent)); - - boolean labeled = isLabeled(); - if(labeled) { - buf.append(indstr+"label"+this.id+":" + new_line_separator); - } - - List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL); - if(first.type == TYPE_TRYCATCH && first.varDefinitions.isEmpty() && isFinally && - !labeled && !first.isLabeled() && (lstSuccs.isEmpty() || !lstSuccs.get(0).explicit)) { - String content = ExprProcessor.jmpWrapper(first, indent, true); - content = content.substring(0, content.length()-new_line_separator.length()); - - buf.append(content); - } else { - buf.append(indstr+"try {" + new_line_separator); - buf.append(ExprProcessor.jmpWrapper(first, indent+1, true)); - buf.append(indstr+"}"); - } - - buf.append((isFinally?" finally": - " catch ("+vars.get(0).toJava(indent)+")")+" {" + new_line_separator); - - if(monitor != null) { - indstr1 = InterpreterUtil.getIndentString(indent+1); - buf.append(indstr1+"if("+monitor.toJava(indent)+") {" + new_line_separator); - } - - buf.append(ExprProcessor.jmpWrapper(handler, indent+1+(monitor != null?1:0), true)); - - if(monitor != null) { - buf.append(indstr1+"}" + new_line_separator); - } - - buf.append(indstr+"}" + new_line_separator); - - return buf.toString(); - } - - public void replaceStatement(Statement oldstat, Statement newstat) { - - if(handler == oldstat) { - handler = newstat; - } - - super.replaceStatement(oldstat, newstat); - } - - public Statement getSimpleCopy() { - - CatchAllStatement cas = new CatchAllStatement(); - - cas.isFinally = this.isFinally; - - if(this.monitor != null) { - cas.monitor = new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER), - VarType.VARTYPE_INT, - (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)); - } - - if(!this.vars.isEmpty()) { - // FIXME: WTF??? vars?! - vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER), - new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Throwable"), - (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR))); - } - - return cas; - } - - public void initSimpleCopy() { - first = stats.get(0); - handler = stats.get(1); - } - - // ***************************************************************************** - // getter and setter methods - // ***************************************************************************** - - public Statement getHandler() { - return handler; - } - - - public void setHandler(Statement handler) { - this.handler = handler; - } - - - public boolean isFinally() { - return isFinally; - } - - - public void setFinally(boolean isFinally) { - this.isFinally = isFinally; - } - - - public VarExprent getMonitor() { - return monitor; - } - - - public void setMonitor(VarExprent monitor) { - this.monitor = monitor; - } - - public List<VarExprent> getVars() { - return vars; - } - + + private Statement handler; + + private boolean isFinally; + + private VarExprent monitor; + + private List<VarExprent> vars = new ArrayList<VarExprent>(); + + // ***************************************************************************** + // constructors + // ***************************************************************************** + + private CatchAllStatement() { + type = Statement.TYPE_CATCHALL; + } + + ; + + private CatchAllStatement(Statement head, Statement handler) { + + this(); + + first = head; + stats.addWithKey(head, head.id); + + this.handler = handler; + stats.addWithKey(handler, handler.id); + + List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL); + if (!lstSuccs.isEmpty()) { + StatEdge edge = lstSuccs.get(0); + if (edge.getType() == StatEdge.TYPE_REGULAR) { + post = edge.getDestination(); + } + } + + vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER), + new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Throwable"), + (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR))); + } + + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public static Statement isHead(Statement head) { + + if (head.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) { + return null; + } + + HashSet<Statement> setHandlers = DecHelper.getUniquePredExceptions(head); + + if (setHandlers.size() != 1) { + return null; + } + + for (StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) { + Statement exc = edge.getDestination(); + + if (edge.getExceptions() == null && setHandlers.contains(exc) && exc.getLastBasicType() == LASTBASICTYPE_GENERAL) { + List<StatEdge> lstSuccs = exc.getSuccessorEdges(STATEDGE_DIRECT_ALL); + if (lstSuccs.isEmpty() || lstSuccs.get(0).getType() != StatEdge.TYPE_REGULAR) { + + if (head.isMonitorEnter() || exc.isMonitorEnter()) { + return null; + } + + if (DecHelper.checkStatementExceptions(Arrays.asList(new Statement[]{head, exc}))) { + return new CatchAllStatement(head, exc); + } + } + } + } + + return null; + } + + public String toJava(int indent) { + String indstr = InterpreterUtil.getIndentString(indent); + String indstr1 = null; + + String new_line_separator = DecompilerContext.getNewLineSeparator(); + + StringBuffer buf = new StringBuffer(); + + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); + + boolean labeled = isLabeled(); + if (labeled) { + buf.append(indstr + "label" + this.id + ":" + new_line_separator); + } + + List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL); + if (first.type == TYPE_TRYCATCH && first.varDefinitions.isEmpty() && isFinally && + !labeled && !first.isLabeled() && (lstSuccs.isEmpty() || !lstSuccs.get(0).explicit)) { + String content = ExprProcessor.jmpWrapper(first, indent, true); + content = content.substring(0, content.length() - new_line_separator.length()); + + buf.append(content); + } + else { + buf.append(indstr + "try {" + new_line_separator); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true)); + buf.append(indstr + "}"); + } + + buf.append((isFinally ? " finally" : + " catch (" + vars.get(0).toJava(indent) + ")") + " {" + new_line_separator); + + if (monitor != null) { + indstr1 = InterpreterUtil.getIndentString(indent + 1); + buf.append(indstr1 + "if(" + monitor.toJava(indent) + ") {" + new_line_separator); + } + + buf.append(ExprProcessor.jmpWrapper(handler, indent + 1 + (monitor != null ? 1 : 0), true)); + + if (monitor != null) { + buf.append(indstr1 + "}" + new_line_separator); + } + + buf.append(indstr + "}" + new_line_separator); + + return buf.toString(); + } + + public void replaceStatement(Statement oldstat, Statement newstat) { + + if (handler == oldstat) { + handler = newstat; + } + + super.replaceStatement(oldstat, newstat); + } + + public Statement getSimpleCopy() { + + CatchAllStatement cas = new CatchAllStatement(); + + cas.isFinally = this.isFinally; + + if (this.monitor != null) { + cas.monitor = new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER), + VarType.VARTYPE_INT, + (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)); + } + + if (!this.vars.isEmpty()) { + // FIXME: WTF??? vars?! + vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER), + new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Throwable"), + (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR))); + } + + return cas; + } + + public void initSimpleCopy() { + first = stats.get(0); + handler = stats.get(1); + } + + // ***************************************************************************** + // getter and setter methods + // ***************************************************************************** + + public Statement getHandler() { + return handler; + } + + + public void setHandler(Statement handler) { + this.handler = handler; + } + + + public boolean isFinally() { + return isFinally; + } + + + public void setFinally(boolean isFinally) { + this.isFinally = isFinally; + } + + + public VarExprent getMonitor() { + return monitor; + } + + + public void setMonitor(VarExprent monitor) { + this.monitor = monitor; + } + + public List<VarExprent> getVars() { + return vars; + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java index 6387d45..17f5636 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java @@ -1,23 +1,20 @@ /* - * Fernflower - The Analytical Java Decompiler - * http://www.reversed-java.com + * Copyright 2000-2014 JetBrains s.r.o. * - * (C) 2008 - 2010, Stiver + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This software is NEITHER public domain NOR free software - * as per GNU License. See license.txt for more details. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This software is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.jetbrains.java.decompiler.modules.decompiler.stats; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.collectors.CounterContainer; @@ -29,178 +26,184 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; import org.jetbrains.java.decompiler.struct.gen.VarType; import org.jetbrains.java.decompiler.util.InterpreterUtil; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + public class CatchStatement extends Statement { - - private List<List<String>> exctstrings = new ArrayList<List<String>>(); - - private List<VarExprent> vars = new ArrayList<VarExprent>(); - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - private CatchStatement() { - type = TYPE_TRYCATCH; - } - - private CatchStatement(Statement head, Statement next, HashSet<Statement> setHandlers) { - - this(); - - first = head; - stats.addWithKey(first, first.id); - - for(StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) { - Statement stat = edge.getDestination(); - - if(setHandlers.contains(stat)) { - stats.addWithKey(stat, stat.id); - exctstrings.add(new ArrayList<String>(edge.getExceptions())); - - vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER), - new VarType(CodeConstants.TYPE_OBJECT, 0, edge.getExceptions().get(0)), // FIXME: for now simply the first type. Should get the first common superclass when possible. - (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR))); - } - } - - if(next != null) { - post = next; - } - - } - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public static Statement isHead(Statement head) { - - if(head.getLastBasicType() != LASTBASICTYPE_GENERAL) { - return null; - } - - HashSet<Statement> setHandlers = DecHelper.getUniquePredExceptions(head); - - if(!setHandlers.isEmpty()) { - - int hnextcount = 0; // either no statements with connection to next, or more than 1 - - Statement next = null; - List<StatEdge> lstHeadSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL); - if(!lstHeadSuccs.isEmpty() && lstHeadSuccs.get(0).getType() == StatEdge.TYPE_REGULAR) { - next = lstHeadSuccs.get(0).getDestination(); - hnextcount = 2; - } - - for(StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) { - Statement stat = edge.getDestination(); - - boolean handlerok = true; - - if(edge.getExceptions() != null && setHandlers.contains(stat)) { - if(stat.getLastBasicType() != LASTBASICTYPE_GENERAL) { - handlerok = false; - } else { - List<StatEdge> lstStatSuccs = stat.getSuccessorEdges(STATEDGE_DIRECT_ALL); - if(!lstStatSuccs.isEmpty() && lstStatSuccs.get(0).getType() == StatEdge.TYPE_REGULAR) { - - Statement statn = lstStatSuccs.get(0).getDestination(); - - if(next == null) { - next = statn; - } else if(next != statn) { - handlerok = false; - } - - if(handlerok) { - hnextcount++; - } - } - } - } else { - handlerok = false; - } - - if(!handlerok) { - setHandlers.remove(stat); - } - } - - if(hnextcount != 1 && !setHandlers.isEmpty()) { - List<Statement> lst = new ArrayList<Statement>(); - lst.add(head); - lst.addAll(setHandlers); - - for(Statement st : lst) { - if(st.isMonitorEnter()) { - return null; - } - } - - if(DecHelper.checkStatementExceptions(lst)) { - return new CatchStatement(head, next, setHandlers); - } - } - } - return null; - } - - public String toJava(int indent) { - String indstr = InterpreterUtil.getIndentString(indent); - StringBuffer buf = new StringBuffer(); - - String new_line_separator = DecompilerContext.getNewLineSeparator(); - - buf.append(ExprProcessor.listToJava(varDefinitions, indent)); - - if(isLabeled()) { - buf.append(indstr+"label"+this.id+":" + new_line_separator); - } - - buf.append(indstr+"try {" + new_line_separator); - buf.append(ExprProcessor.jmpWrapper(first, indent+1, true)); - buf.append(indstr+"}"); - - for(int i=1;i<stats.size();i++) { - List<String> exception_types = exctstrings.get(i - 1); - - buf.append(" catch ("); - if(exception_types.size() > 1) { // multi-catch, Java 7 style - for(int exc_index = 1; exc_index < exception_types.size(); ++exc_index) { - VarType exc_type = new VarType(CodeConstants.TYPE_OBJECT, 0, exception_types.get(exc_index)); - String exc_type_name = ExprProcessor.getCastTypeName(exc_type); - - buf.append(exc_type_name + " | "); - } - } - buf.append(vars.get(i-1).toJava(indent)); - buf.append(") {"+new_line_separator+ExprProcessor.jmpWrapper(stats.get(i), indent+1, true)+indstr+"}"); - } - buf.append(new_line_separator); - - return buf.toString(); - } - - public Statement getSimpleCopy() { - - CatchStatement cs = new CatchStatement(); - - for(List<String> exc : this.exctstrings) { - cs.exctstrings.add(new ArrayList<String>(exc)); - cs.vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER), - new VarType(CodeConstants.TYPE_OBJECT, 0, exc.get(0)), - (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR))); - } - - return cs; - } - - // ***************************************************************************** - // getter and setter methods - // ***************************************************************************** - - public List<VarExprent> getVars() { - return vars; - } - + + private List<List<String>> exctstrings = new ArrayList<List<String>>(); + + private List<VarExprent> vars = new ArrayList<VarExprent>(); + + // ***************************************************************************** + // constructors + // ***************************************************************************** + + private CatchStatement() { + type = TYPE_TRYCATCH; + } + + private CatchStatement(Statement head, Statement next, HashSet<Statement> setHandlers) { + + this(); + + first = head; + stats.addWithKey(first, first.id); + + for (StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) { + Statement stat = edge.getDestination(); + + if (setHandlers.contains(stat)) { + stats.addWithKey(stat, stat.id); + exctstrings.add(new ArrayList<String>(edge.getExceptions())); + + vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER), + new VarType(CodeConstants.TYPE_OBJECT, 0, edge.getExceptions().get(0)), + // FIXME: for now simply the first type. Should get the first common superclass when possible. + (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR))); + } + } + + if (next != null) { + post = next; + } + } + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public static Statement isHead(Statement head) { + + if (head.getLastBasicType() != LASTBASICTYPE_GENERAL) { + return null; + } + + HashSet<Statement> setHandlers = DecHelper.getUniquePredExceptions(head); + + if (!setHandlers.isEmpty()) { + + int hnextcount = 0; // either no statements with connection to next, or more than 1 + + Statement next = null; + List<StatEdge> lstHeadSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL); + if (!lstHeadSuccs.isEmpty() && lstHeadSuccs.get(0).getType() == StatEdge.TYPE_REGULAR) { + next = lstHeadSuccs.get(0).getDestination(); + hnextcount = 2; + } + + for (StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) { + Statement stat = edge.getDestination(); + + boolean handlerok = true; + + if (edge.getExceptions() != null && setHandlers.contains(stat)) { + if (stat.getLastBasicType() != LASTBASICTYPE_GENERAL) { + handlerok = false; + } + else { + List<StatEdge> lstStatSuccs = stat.getSuccessorEdges(STATEDGE_DIRECT_ALL); + if (!lstStatSuccs.isEmpty() && lstStatSuccs.get(0).getType() == StatEdge.TYPE_REGULAR) { + + Statement statn = lstStatSuccs.get(0).getDestination(); + + if (next == null) { + next = statn; + } + else if (next != statn) { + handlerok = false; + } + + if (handlerok) { + hnextcount++; + } + } + } + } + else { + handlerok = false; + } + + if (!handlerok) { + setHandlers.remove(stat); + } + } + + if (hnextcount != 1 && !setHandlers.isEmpty()) { + List<Statement> lst = new ArrayList<Statement>(); + lst.add(head); + lst.addAll(setHandlers); + + for (Statement st : lst) { + if (st.isMonitorEnter()) { + return null; + } + } + + if (DecHelper.checkStatementExceptions(lst)) { + return new CatchStatement(head, next, setHandlers); + } + } + } + return null; + } + + public String toJava(int indent) { + String indstr = InterpreterUtil.getIndentString(indent); + StringBuffer buf = new StringBuffer(); + + String new_line_separator = DecompilerContext.getNewLineSeparator(); + + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); + + if (isLabeled()) { + buf.append(indstr + "label" + this.id + ":" + new_line_separator); + } + + buf.append(indstr + "try {" + new_line_separator); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true)); + buf.append(indstr + "}"); + + for (int i = 1; i < stats.size(); i++) { + List<String> exception_types = exctstrings.get(i - 1); + + buf.append(" catch ("); + if (exception_types.size() > 1) { // multi-catch, Java 7 style + for (int exc_index = 1; exc_index < exception_types.size(); ++exc_index) { + VarType exc_type = new VarType(CodeConstants.TYPE_OBJECT, 0, exception_types.get(exc_index)); + String exc_type_name = ExprProcessor.getCastTypeName(exc_type); + + buf.append(exc_type_name + " | "); + } + } + buf.append(vars.get(i - 1).toJava(indent)); + buf.append(") {" + new_line_separator + ExprProcessor.jmpWrapper(stats.get(i), indent + 1, true) + indstr + "}"); + } + buf.append(new_line_separator); + + return buf.toString(); + } + + public Statement getSimpleCopy() { + + CatchStatement cs = new CatchStatement(); + + for (List<String> exc : this.exctstrings) { + cs.exctstrings.add(new ArrayList<String>(exc)); + cs.vars.add(new VarExprent(DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER), + new VarType(CodeConstants.TYPE_OBJECT, 0, exc.get(0)), + (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR))); + } + + return cs; + } + + // ***************************************************************************** + // getter and setter methods + // ***************************************************************************** + + public List<VarExprent> getVars() { + return vars; + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java index 604e36f..2bd8e3a 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java @@ -1,221 +1,221 @@ /* - * Fernflower - The Analytical Java Decompiler - * http://www.reversed-java.com + * Copyright 2000-2014 JetBrains s.r.o. * - * (C) 2008 - 2010, Stiver + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This software is NEITHER public domain NOR free software - * as per GNU License. See license.txt for more details. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This software is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.jetbrains.java.decompiler.modules.decompiler.stats; -import java.util.ArrayList; -import java.util.List; - import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; import org.jetbrains.java.decompiler.util.InterpreterUtil; +import java.util.ArrayList; +import java.util.List; + public class DoStatement extends Statement { - - public static final int LOOP_DO = 0; - public static final int LOOP_DOWHILE = 1; - public static final int LOOP_WHILE = 2; - public static final int LOOP_FOR = 3; - - private int looptype; - - private List<Exprent> initExprent = new ArrayList<Exprent>(); - private List<Exprent> conditionExprent = new ArrayList<Exprent>(); - private List<Exprent> incExprent = new ArrayList<Exprent>(); - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - private DoStatement() { - type = Statement.TYPE_DO; - looptype = LOOP_DO; - - initExprent.add(null); - conditionExprent.add(null); - incExprent.add(null); - } - - private DoStatement(Statement head) { - - this(); - - first = head; - stats.addWithKey(first, first.id); - - // post is always null! - } - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public static Statement isHead(Statement head) { - - if(head.getLastBasicType() == LASTBASICTYPE_GENERAL && !head.isMonitorEnter()) { - - // at most one outgoing edge - StatEdge edge = null; - List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL); - if(!lstSuccs.isEmpty()) { - edge = lstSuccs.get(0); - } - - // regular loop - if(edge!=null && edge.getType() == StatEdge.TYPE_REGULAR && edge.getDestination() == head) { - return new DoStatement(head); - } - - // continues - if(head.type != TYPE_DO && (edge == null || edge.getType() != StatEdge.TYPE_REGULAR) && - head.getContinueSet().contains(head.getBasichead())) { - return new DoStatement(head); - } - } - - return null; - } - - public String toJava(int indent) { - String indstr = InterpreterUtil.getIndentString(indent); - StringBuffer buf = new StringBuffer(); - - String new_line_separator = DecompilerContext.getNewLineSeparator(); - - buf.append(ExprProcessor.listToJava(varDefinitions, indent)); - - if(isLabeled()) { - buf.append(indstr+"label"+this.id+":" + new_line_separator); - } - - switch(looptype) { - case LOOP_DO: - buf.append(indstr+"while(true) {" + new_line_separator); - buf.append(ExprProcessor.jmpWrapper(first, indent+1, true)); - buf.append(indstr+"}" + new_line_separator); - break; - case LOOP_DOWHILE: - buf.append(indstr+"do {" + new_line_separator); - buf.append(ExprProcessor.jmpWrapper(first, indent+1, true)); - buf.append(indstr+"} while("+conditionExprent.get(0).toJava(indent)+");" + new_line_separator); - break; - case LOOP_WHILE: - buf.append(indstr+"while("+conditionExprent.get(0).toJava(indent)+") {" + new_line_separator); - buf.append(ExprProcessor.jmpWrapper(first, indent+1, true)); - buf.append(indstr+"}" + new_line_separator); - break; - case LOOP_FOR: - buf.append(indstr+"for("+(initExprent.get(0)==null?"":initExprent.get(0).toJava(indent))+ - "; "+conditionExprent.get(0).toJava(indent)+"; "+incExprent.get(0).toJava(indent)+") {" + new_line_separator); - buf.append(ExprProcessor.jmpWrapper(first, indent+1, true)); - buf.append(indstr+"}" + new_line_separator); - } - - return buf.toString(); - } - - public List<Object> getSequentialObjects() { - - List<Object> lst = new ArrayList<Object>(); - - switch(looptype) { - case LOOP_FOR: - if(getInitExprent() != null) { - lst.add(getInitExprent()); - } - case LOOP_WHILE: - lst.add(getConditionExprent()); - } - - lst.add(first); - - switch(looptype) { - case LOOP_DOWHILE: - lst.add(getConditionExprent()); - break; - case LOOP_FOR: - lst.add(getIncExprent()); - } - - return lst; - } - - public void replaceExprent(Exprent oldexpr, Exprent newexpr) { - if(initExprent.get(0) == oldexpr) { - initExprent.set(0, newexpr); - } - if(conditionExprent.get(0) == oldexpr) { - conditionExprent.set(0, newexpr); - } - if(incExprent.get(0) == oldexpr) { - incExprent.set(0, newexpr); - } - } - - public Statement getSimpleCopy() { - return new DoStatement(); - } - - // ***************************************************************************** - // getter and setter methods - // ***************************************************************************** - - public List<Exprent> getInitExprentList() { - return initExprent; - } - - public List<Exprent> getConditionExprentList() { - return conditionExprent; - } - - public List<Exprent> getIncExprentList() { - return incExprent; - } - - public Exprent getConditionExprent() { - return conditionExprent.get(0); - } - - public void setConditionExprent(Exprent conditionExprent) { - this.conditionExprent.set(0, conditionExprent); - } - - public Exprent getIncExprent() { - return incExprent.get(0); - } - - public void setIncExprent(Exprent incExprent) { - this.incExprent.set(0, incExprent); - } - - public Exprent getInitExprent() { - return initExprent.get(0); - } - - public void setInitExprent(Exprent initExprent) { - this.initExprent.set(0, initExprent); - } - - public int getLooptype() { - return looptype; - } - - public void setLooptype(int looptype) { - this.looptype = looptype; - } - + + public static final int LOOP_DO = 0; + public static final int LOOP_DOWHILE = 1; + public static final int LOOP_WHILE = 2; + public static final int LOOP_FOR = 3; + + private int looptype; + + private List<Exprent> initExprent = new ArrayList<Exprent>(); + private List<Exprent> conditionExprent = new ArrayList<Exprent>(); + private List<Exprent> incExprent = new ArrayList<Exprent>(); + + // ***************************************************************************** + // constructors + // ***************************************************************************** + + private DoStatement() { + type = Statement.TYPE_DO; + looptype = LOOP_DO; + + initExprent.add(null); + conditionExprent.add(null); + incExprent.add(null); + } + + private DoStatement(Statement head) { + + this(); + + first = head; + stats.addWithKey(first, first.id); + + // post is always null! + } + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public static Statement isHead(Statement head) { + + if (head.getLastBasicType() == LASTBASICTYPE_GENERAL && !head.isMonitorEnter()) { + + // at most one outgoing edge + StatEdge edge = null; + List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL); + if (!lstSuccs.isEmpty()) { + edge = lstSuccs.get(0); + } + + // regular loop + if (edge != null && edge.getType() == StatEdge.TYPE_REGULAR && edge.getDestination() == head) { + return new DoStatement(head); + } + + // continues + if (head.type != TYPE_DO && (edge == null || edge.getType() != StatEdge.TYPE_REGULAR) && + head.getContinueSet().contains(head.getBasichead())) { + return new DoStatement(head); + } + } + + return null; + } + + public String toJava(int indent) { + String indstr = InterpreterUtil.getIndentString(indent); + StringBuffer buf = new StringBuffer(); + + String new_line_separator = DecompilerContext.getNewLineSeparator(); + + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); + + if (isLabeled()) { + buf.append(indstr + "label" + this.id + ":" + new_line_separator); + } + + switch (looptype) { + case LOOP_DO: + buf.append(indstr + "while(true) {" + new_line_separator); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true)); + buf.append(indstr + "}" + new_line_separator); + break; + case LOOP_DOWHILE: + buf.append(indstr + "do {" + new_line_separator); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true)); + buf.append(indstr + "} while(" + conditionExprent.get(0).toJava(indent) + ");" + new_line_separator); + break; + case LOOP_WHILE: + buf.append(indstr + "while(" + conditionExprent.get(0).toJava(indent) + ") {" + new_line_separator); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true)); + buf.append(indstr + "}" + new_line_separator); + break; + case LOOP_FOR: + buf.append(indstr + "for(" + (initExprent.get(0) == null ? "" : initExprent.get(0).toJava(indent)) + + "; " + conditionExprent.get(0).toJava(indent) + "; " + incExprent.get(0).toJava(indent) + ") {" + new_line_separator); + buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true)); + buf.append(indstr + "}" + new_line_separator); + } + + return buf.toString(); + } + + public List<Object> getSequentialObjects() { + + List<Object> lst = new ArrayList<Object>(); + + switch (looptype) { + case LOOP_FOR: + if (getInitExprent() != null) { + lst.add(getInitExprent()); + } + case LOOP_WHILE: + lst.add(getConditionExprent()); + } + + lst.add(first); + + switch (looptype) { + case LOOP_DOWHILE: + lst.add(getConditionExprent()); + break; + case LOOP_FOR: + lst.add(getIncExprent()); + } + + return lst; + } + + public void replaceExprent(Exprent oldexpr, Exprent newexpr) { + if (initExprent.get(0) == oldexpr) { + initExprent.set(0, newexpr); + } + if (conditionExprent.get(0) == oldexpr) { + conditionExprent.set(0, newexpr); + } + if (incExprent.get(0) == oldexpr) { + incExprent.set(0, newexpr); + } + } + + public Statement getSimpleCopy() { + return new DoStatement(); + } + + // ***************************************************************************** + // getter and setter methods + // ***************************************************************************** + + public List<Exprent> getInitExprentList() { + return initExprent; + } + + public List<Exprent> getConditionExprentList() { + return conditionExprent; + } + + public List<Exprent> getIncExprentList() { + return incExprent; + } + + public Exprent getConditionExprent() { + return conditionExprent.get(0); + } + + public void setConditionExprent(Exprent conditionExprent) { + this.conditionExprent.set(0, conditionExprent); + } + + public Exprent getIncExprent() { + return incExprent.get(0); + } + + public void setIncExprent(Exprent incExprent) { + this.incExprent.set(0, incExprent); + } + + public Exprent getInitExprent() { + return initExprent.get(0); + } + + public void setInitExprent(Exprent initExprent) { + this.initExprent.set(0, initExprent); + } + + public int getLooptype() { + return looptype; + } + + public void setLooptype(int looptype) { + this.looptype = looptype; + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java index 9cfaeb4..9988881 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java @@ -1,75 +1,74 @@ /* - * Fernflower - The Analytical Java Decompiler - * http://www.reversed-java.com + * Copyright 2000-2014 JetBrains s.r.o. * - * (C) 2008 - 2010, Stiver + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This software is NEITHER public domain NOR free software - * as per GNU License. See license.txt for more details. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This software is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.jetbrains.java.decompiler.modules.decompiler.stats; -import java.util.Collection; -import java.util.HashSet; - import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.util.InterpreterUtil; +import java.util.Collection; +import java.util.HashSet; public class GeneralStatement extends Statement { - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - private GeneralStatement() { - type = Statement.TYPE_GENERAL; - } - - public GeneralStatement(Statement head, Collection<Statement> statements, Statement post) { - - this(); - - first = head; - stats.addWithKey(head, head.id); - - HashSet<Statement> set = new HashSet<Statement>(statements); - set.remove(head); - - for(Statement st : set) { - stats.addWithKey(st, st.id); - } - - this.post = post; - } - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public String toJava(int indent) { - String indstr = InterpreterUtil.getIndentString(indent); - StringBuffer buf = new StringBuffer(); - - String new_line_separator = DecompilerContext.getNewLineSeparator(); - - if(isLabeled()) { - buf.append(indstr+"label"+this.id+":" + new_line_separator); - } - - buf.append(indstr+"abstract statement {" + new_line_separator); - for(int i=0;i<stats.size();i++) { - buf.append(stats.get(i).toJava(indent+1)); - } - buf.append(indstr+"}"); - - return buf.toString(); - } - + + // ***************************************************************************** + // constructors + // ***************************************************************************** + + private GeneralStatement() { + type = Statement.TYPE_GENERAL; + } + + public GeneralStatement(Statement head, Collection<Statement> statements, Statement post) { + + this(); + + first = head; + stats.addWithKey(head, head.id); + + HashSet<Statement> set = new HashSet<Statement>(statements); + set.remove(head); + + for (Statement st : set) { + stats.addWithKey(st, st.id); + } + + this.post = post; + } + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public String toJava(int indent) { + String indstr = InterpreterUtil.getIndentString(indent); + StringBuffer buf = new StringBuffer(); + + String new_line_separator = DecompilerContext.getNewLineSeparator(); + + if (isLabeled()) { + buf.append(indstr + "label" + this.id + ":" + new_line_separator); + } + + buf.append(indstr + "abstract statement {" + new_line_separator); + for (int i = 0; i < stats.size(); i++) { + buf.append(stats.get(i).toJava(indent + 1)); + } + buf.append(indstr + "}"); + + return buf.toString(); + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java index 3e3e20b..0b05981 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java @@ -1,22 +1,20 @@ /* - * Fernflower - The Analytical Java Decompiler - * http://www.reversed-java.com + * Copyright 2000-2014 JetBrains s.r.o. * - * (C) 2008 - 2010, Stiver + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This software is NEITHER public domain NOR free software - * as per GNU License. See license.txt for more details. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This software is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.jetbrains.java.decompiler.modules.decompiler.stats; -import java.util.ArrayList; -import java.util.List; - import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.modules.decompiler.DecHelper; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; @@ -25,380 +23,394 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent; import org.jetbrains.java.decompiler.util.InterpreterUtil; +import java.util.ArrayList; +import java.util.List; + public class IfStatement extends Statement { - public static int IFTYPE_IF = 0; - public static int IFTYPE_IFELSE = 1; - - public int iftype; - - // ***************************************************************************** - // private fields - // ***************************************************************************** - - private Statement ifstat; - private Statement elsestat; - - private StatEdge ifedge; - private StatEdge elseedge; - - private boolean negated = false; - - private boolean iffflag; - - private List<Exprent> headexprent = new ArrayList<Exprent>(); // contains IfExprent - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - private IfStatement() { - type = TYPE_IF; - - headexprent.add(null); - } - - private IfStatement(Statement head, int regedges, Statement postst) { - - this(); - - first = head; - stats.addWithKey(head, head.id); - - List<StatEdge> lstHeadSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL); - - switch(regedges) { - case 0: - ifstat = null; - elsestat = null; - - break; - case 1: - ifstat = null; - elsestat = null; - - StatEdge edgeif = lstHeadSuccs.get(1); - if(edgeif.getType() != StatEdge.TYPE_REGULAR) { - post = lstHeadSuccs.get(0).getDestination(); - } else { - post = edgeif.getDestination(); - negated = true; - } - break; - case 2: - elsestat = lstHeadSuccs.get(0).getDestination(); - ifstat = lstHeadSuccs.get(1).getDestination(); - - List<StatEdge> lstSucc = ifstat.getSuccessorEdges(StatEdge.TYPE_REGULAR); - List<StatEdge> lstSucc1 = elsestat.getSuccessorEdges(StatEdge.TYPE_REGULAR); - - if(ifstat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size()>1 || lstSucc.size()>1) { - post = ifstat; - } else if(elsestat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size()>1 || lstSucc1.size()>1) { - post = elsestat; - } else { - if(lstSucc.size() == 0){ - post = elsestat; - } else if(lstSucc1.size() == 0){ - post = ifstat; - } - } - - if(ifstat == post) { - if(elsestat != post) { - ifstat = elsestat; - negated = true; - } else { - ifstat = null; - } - elsestat = null; - } else if(elsestat == post) { - elsestat = null; - } else { - post = postst; - } - - if(elsestat == null) { - regedges = 1; // if without else - } - } - - ifedge = lstHeadSuccs.get(negated?0:1); - elseedge = (regedges == 2)?lstHeadSuccs.get(negated?1:0):null; - - iftype = (regedges == 2)?IFTYPE_IFELSE:IFTYPE_IF; - - if(iftype == IFTYPE_IF) { - if(regedges == 0) { - StatEdge edge = lstHeadSuccs.get(0); - head.removeSuccessor(edge); - edge.setSource(this); - this.addSuccessor(edge); - } else if(regedges == 1) { - StatEdge edge = lstHeadSuccs.get(negated?1:0); - head.removeSuccessor(edge); - } - } - - if(ifstat != null) { - stats.addWithKey(ifstat, ifstat.id); - } - - if(elsestat != null) { - stats.addWithKey(elsestat, elsestat.id); - } - - if(post == head) { - post = this; - } - - } - - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public static Statement isHead(Statement head) { - - if(head.type == TYPE_BASICBLOCK && head.getLastBasicType() == LASTBASICTYPE_IF) { - int regsize = head.getSuccessorEdges(StatEdge.TYPE_REGULAR).size(); - - Statement p = null; - - boolean ok = (regsize < 2); - if(!ok) { - List<Statement> lst = new ArrayList<Statement>(); - if(DecHelper.isChoiceStatement(head, lst)) { - p = lst.remove(0); - - for(Statement st : lst) { - if(st.isMonitorEnter()) { - return null; - } - } - - ok = DecHelper.checkStatementExceptions(lst); - } - } - - if(ok) { - return new IfStatement(head, regsize, p); - } - } - - return null; - } - - public String toJava(int indent) { - String indstr = InterpreterUtil.getIndentString(indent); - StringBuffer buf = new StringBuffer(); - - String new_line_separator = DecompilerContext.getNewLineSeparator(); - - buf.append(ExprProcessor.listToJava(varDefinitions, indent)); - buf.append(first.toJava(indent)); - - if(isLabeled()) { - buf.append(indstr+"label"+this.id+":" + new_line_separator); - } - - buf.append(indstr+headexprent.get(0).toJava(indent)+" {" + new_line_separator); - - if(ifstat==null) { - buf.append(InterpreterUtil.getIndentString(indent+1)); - - if(ifedge.explicit) { - if(ifedge.getType() == StatEdge.TYPE_BREAK) { - // break - buf.append("break"); - } else { - // continue - buf.append("continue"); - } - - if(ifedge.labeled) { - buf.append(" label"+ifedge.closure.id); - } - } - buf.append(";" + new_line_separator); - } else { - buf.append(ExprProcessor.jmpWrapper(ifstat, indent+1, true)); - } - - boolean elseif = false; - - if(elsestat != null) { - if(elsestat.type == Statement.TYPE_IF - && elsestat.varDefinitions.isEmpty() && elsestat.getFirst().getExprents().isEmpty() && - !elsestat.isLabeled() && - (elsestat.getSuccessorEdges(STATEDGE_DIRECT_ALL).isEmpty() - || !elsestat.getSuccessorEdges(STATEDGE_DIRECT_ALL).get(0).explicit)) { // else if - String content = ExprProcessor.jmpWrapper(elsestat, indent, false); - content = content.substring(indstr.length()); - - buf.append(indstr+"} else "); - buf.append(content); - - elseif = true; - } else { - String content = ExprProcessor.jmpWrapper(elsestat, indent+1, false); - - if(content.length() > 0) { - buf.append(indstr+"} else {" + new_line_separator); - buf.append(content); - } - } - } - - if(!elseif) { - buf.append(indstr+"}" + new_line_separator); - } - - return buf.toString(); - } - - public void initExprents() { - - IfExprent ifexpr = (IfExprent)first.getExprents().remove(first.getExprents().size()-1); - - if(negated) { - ifexpr = (IfExprent)ifexpr.copy(); - ifexpr.negateIf(); - } - - headexprent.set(0, ifexpr); - } - - public List<Object> getSequentialObjects() { - - List<Object> lst = new ArrayList<Object>(stats); - lst.add(1, headexprent.get(0)); - - return lst; - } - - public void replaceExprent(Exprent oldexpr, Exprent newexpr) { - if(headexprent.get(0) == oldexpr) { - headexprent.set(0, newexpr); - } - } - - public void replaceStatement(Statement oldstat, Statement newstat) { - - super.replaceStatement(oldstat, newstat); - - if(ifstat == oldstat) { - ifstat = newstat; - } - - if(elsestat == oldstat) { - elsestat = newstat; - } - - List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL); - - if(iftype == IFTYPE_IF) { - ifedge = lstSuccs.get(0); - elseedge = null; - } else { - StatEdge edge0 = lstSuccs.get(0); - StatEdge edge1 = lstSuccs.get(1); - if(edge0.getDestination() == ifstat) { - ifedge = edge0; - elseedge = edge1; - } else { - ifedge = edge1; - elseedge = edge0; - } - } - } - - public Statement getSimpleCopy() { - - IfStatement is = new IfStatement(); - is.iftype = this.iftype; - is.negated = this.negated; - is.iffflag = this.iffflag; - - return is; - } - - public void initSimpleCopy() { - - first = stats.get(0); - - List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL); - ifedge = lstSuccs.get((iftype == IFTYPE_IF || negated)?0:1); - if(stats.size() > 1) { - ifstat = stats.get(1); - } - - if(iftype == IFTYPE_IFELSE) { - elseedge = lstSuccs.get(negated?1:0); - elsestat = stats.get(2); - } - - } - - // ***************************************************************************** - // getter and setter methods - // ***************************************************************************** - - public Statement getElsestat() { - return elsestat; - } - - public void setElsestat(Statement elsestat) { - this.elsestat = elsestat; - } - - public Statement getIfstat() { - return ifstat; - } - - public void setIfstat(Statement ifstat) { - this.ifstat = ifstat; - } - - public boolean isNegated() { - return negated; - } - - public void setNegated(boolean negated) { - this.negated = negated; - } - - public List<Exprent> getHeadexprentList() { - return headexprent; - } - - public IfExprent getHeadexprent() { - return (IfExprent)headexprent.get(0); - } - - public boolean isIffflag() { - return iffflag; - } - - public void setIffflag(boolean iffflag) { - this.iffflag = iffflag; - } - - public void setElseEdge(StatEdge elseedge) { - this.elseedge = elseedge; - } - - public void setIfEdge(StatEdge ifedge) { - this.ifedge = ifedge; - } - - public StatEdge getIfEdge() { - return ifedge; - } - - public StatEdge getElseEdge() { - return elseedge; - } + public static int IFTYPE_IF = 0; + public static int IFTYPE_IFELSE = 1; + + public int iftype; + + // ***************************************************************************** + // private fields + // ***************************************************************************** + + private Statement ifstat; + private Statement elsestat; + + private StatEdge ifedge; + private StatEdge elseedge; + + private boolean negated = false; + + private boolean iffflag; + + private List<Exprent> headexprent = new ArrayList<Exprent>(); // contains IfExprent + + // ***************************************************************************** + // constructors + // ***************************************************************************** + + private IfStatement() { + type = TYPE_IF; + + headexprent.add(null); + } + + private IfStatement(Statement head, int regedges, Statement postst) { + + this(); + + first = head; + stats.addWithKey(head, head.id); + + List<StatEdge> lstHeadSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL); + + switch (regedges) { + case 0: + ifstat = null; + elsestat = null; + + break; + case 1: + ifstat = null; + elsestat = null; + + StatEdge edgeif = lstHeadSuccs.get(1); + if (edgeif.getType() != StatEdge.TYPE_REGULAR) { + post = lstHeadSuccs.get(0).getDestination(); + } + else { + post = edgeif.getDestination(); + negated = true; + } + break; + case 2: + elsestat = lstHeadSuccs.get(0).getDestination(); + ifstat = lstHeadSuccs.get(1).getDestination(); + + List<StatEdge> lstSucc = ifstat.getSuccessorEdges(StatEdge.TYPE_REGULAR); + List<StatEdge> lstSucc1 = elsestat.getSuccessorEdges(StatEdge.TYPE_REGULAR); + + if (ifstat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size() > 1 || lstSucc.size() > 1) { + post = ifstat; + } + else if (elsestat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size() > 1 || lstSucc1.size() > 1) { + post = elsestat; + } + else { + if (lstSucc.size() == 0) { + post = elsestat; + } + else if (lstSucc1.size() == 0) { + post = ifstat; + } + } + + if (ifstat == post) { + if (elsestat != post) { + ifstat = elsestat; + negated = true; + } + else { + ifstat = null; + } + elsestat = null; + } + else if (elsestat == post) { + elsestat = null; + } + else { + post = postst; + } + + if (elsestat == null) { + regedges = 1; // if without else + } + } + + ifedge = lstHeadSuccs.get(negated ? 0 : 1); + elseedge = (regedges == 2) ? lstHeadSuccs.get(negated ? 1 : 0) : null; + + iftype = (regedges == 2) ? IFTYPE_IFELSE : IFTYPE_IF; + + if (iftype == IFTYPE_IF) { + if (regedges == 0) { + StatEdge edge = lstHeadSuccs.get(0); + head.removeSuccessor(edge); + edge.setSource(this); + this.addSuccessor(edge); + } + else if (regedges == 1) { + StatEdge edge = lstHeadSuccs.get(negated ? 1 : 0); + head.removeSuccessor(edge); + } + } + + if (ifstat != null) { + stats.addWithKey(ifstat, ifstat.id); + } + + if (elsestat != null) { + stats.addWithKey(elsestat, elsestat.id); + } + + if (post == head) { + post = this; + } + } + + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public static Statement isHead(Statement head) { + + if (head.type == TYPE_BASICBLOCK && head.getLastBasicType() == LASTBASICTYPE_IF) { + int regsize = head.getSuccessorEdges(StatEdge.TYPE_REGULAR).size(); + + Statement p = null; + + boolean ok = (regsize < 2); + if (!ok) { + List<Statement> lst = new ArrayList<Statement>(); + if (DecHelper.isChoiceStatement(head, lst)) { + p = lst.remove(0); + + for (Statement st : lst) { + if (st.isMonitorEnter()) { + return null; + } + } + + ok = DecHelper.checkStatementExceptions(lst); + } + } + + if (ok) { + return new IfStatement(head, regsize, p); + } + } + + return null; + } + + public String toJava(int indent) { + String indstr = InterpreterUtil.getIndentString(indent); + StringBuffer buf = new StringBuffer(); + + String new_line_separator = DecompilerContext.getNewLineSeparator(); + + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); + buf.append(first.toJava(indent)); + + if (isLabeled()) { + buf.append(indstr + "label" + this.id + ":" + new_line_separator); + } + + buf.append(indstr + headexprent.get(0).toJava(indent) + " {" + new_line_separator); + + if (ifstat == null) { + buf.append(InterpreterUtil.getIndentString(indent + 1)); + + if (ifedge.explicit) { + if (ifedge.getType() == StatEdge.TYPE_BREAK) { + // break + buf.append("break"); + } + else { + // continue + buf.append("continue"); + } + + if (ifedge.labeled) { + buf.append(" label" + ifedge.closure.id); + } + } + buf.append(";" + new_line_separator); + } + else { + buf.append(ExprProcessor.jmpWrapper(ifstat, indent + 1, true)); + } + + boolean elseif = false; + + if (elsestat != null) { + if (elsestat.type == Statement.TYPE_IF + && elsestat.varDefinitions.isEmpty() && elsestat.getFirst().getExprents().isEmpty() && + !elsestat.isLabeled() && + (elsestat.getSuccessorEdges(STATEDGE_DIRECT_ALL).isEmpty() + || !elsestat.getSuccessorEdges(STATEDGE_DIRECT_ALL).get(0).explicit)) { // else if + String content = ExprProcessor.jmpWrapper(elsestat, indent, false); + content = content.substring(indstr.length()); + + buf.append(indstr + "} else "); + buf.append(content); + + elseif = true; + } + else { + String content = ExprProcessor.jmpWrapper(elsestat, indent + 1, false); + + if (content.length() > 0) { + buf.append(indstr + "} else {" + new_line_separator); + buf.append(content); + } + } + } + + if (!elseif) { + buf.append(indstr + "}" + new_line_separator); + } + + return buf.toString(); + } + + public void initExprents() { + + IfExprent ifexpr = (IfExprent)first.getExprents().remove(first.getExprents().size() - 1); + + if (negated) { + ifexpr = (IfExprent)ifexpr.copy(); + ifexpr.negateIf(); + } + + headexprent.set(0, ifexpr); + } + + public List<Object> getSequentialObjects() { + + List<Object> lst = new ArrayList<Object>(stats); + lst.add(1, headexprent.get(0)); + + return lst; + } + + public void replaceExprent(Exprent oldexpr, Exprent newexpr) { + if (headexprent.get(0) == oldexpr) { + headexprent.set(0, newexpr); + } + } + + public void replaceStatement(Statement oldstat, Statement newstat) { + + super.replaceStatement(oldstat, newstat); + + if (ifstat == oldstat) { + ifstat = newstat; + } + + if (elsestat == oldstat) { + elsestat = newstat; + } + + List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL); + + if (iftype == IFTYPE_IF) { + ifedge = lstSuccs.get(0); + elseedge = null; + } + else { + StatEdge edge0 = lstSuccs.get(0); + StatEdge edge1 = lstSuccs.get(1); + if (edge0.getDestination() == ifstat) { + ifedge = edge0; + elseedge = edge1; + } + else { + ifedge = edge1; + elseedge = edge0; + } + } + } + + public Statement getSimpleCopy() { + + IfStatement is = new IfStatement(); + is.iftype = this.iftype; + is.negated = this.negated; + is.iffflag = this.iffflag; + + return is; + } + + public void initSimpleCopy() { + + first = stats.get(0); + + List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL); + ifedge = lstSuccs.get((iftype == IFTYPE_IF || negated) ? 0 : 1); + if (stats.size() > 1) { + ifstat = stats.get(1); + } + + if (iftype == IFTYPE_IFELSE) { + elseedge = lstSuccs.get(negated ? 1 : 0); + elsestat = stats.get(2); + } + } + + // ***************************************************************************** + // getter and setter methods + // ***************************************************************************** + + public Statement getElsestat() { + return elsestat; + } + + public void setElsestat(Statement elsestat) { + this.elsestat = elsestat; + } + + public Statement getIfstat() { + return ifstat; + } + + public void setIfstat(Statement ifstat) { + this.ifstat = ifstat; + } + + public boolean isNegated() { + return negated; + } + + public void setNegated(boolean negated) { + this.negated = negated; + } + + public List<Exprent> getHeadexprentList() { + return headexprent; + } + + public IfExprent getHeadexprent() { + return (IfExprent)headexprent.get(0); + } + + public boolean isIffflag() { + return iffflag; + } + + public void setIffflag(boolean iffflag) { + this.iffflag = iffflag; + } + + public void setElseEdge(StatEdge elseedge) { + this.elseedge = elseedge; + } + + public void setIfEdge(StatEdge ifedge) { + this.ifedge = ifedge; + } + + public StatEdge getIfEdge() { + return ifedge; + } + + public StatEdge getElseEdge() { + return elseedge; + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java index c34888e..2a69447 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java @@ -1,17 +1,18 @@ /* - * Fernflower - The Analytical Java Decompiler - * http://www.reversed-java.com + * Copyright 2000-2014 JetBrains s.r.o. * - * (C) 2008 - 2010, Stiver + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This software is NEITHER public domain NOR free software - * as per GNU License. See license.txt for more details. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This software is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.jetbrains.java.decompiler.modules.decompiler.stats; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; @@ -19,31 +20,29 @@ import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; public class RootStatement extends Statement { - private Statement dummyExit; - - public RootStatement(Statement head, Statement dummyExit) { - - type = Statement.TYPE_ROOT; - - first = head; - this.dummyExit = dummyExit; - - stats.addWithKey(first, first.id); - first.setParent(this); - - } - - public String toJava(int indent) { - return ExprProcessor.listToJava(varDefinitions, indent)+ - first.toJava(indent); - } - - public Statement getDummyExit() { - return dummyExit; - } - - public void setDummyExit(Statement dummyExit) { - this.dummyExit = dummyExit; - } - + private Statement dummyExit; + + public RootStatement(Statement head, Statement dummyExit) { + + type = Statement.TYPE_ROOT; + + first = head; + this.dummyExit = dummyExit; + + stats.addWithKey(first, first.id); + first.setParent(this); + } + + public String toJava(int indent) { + return ExprProcessor.listToJava(varDefinitions, indent) + + first.toJava(indent); + } + + public Statement getDummyExit() { + return dummyExit; + } + + public void setDummyExit(Statement dummyExit) { + this.dummyExit = dummyExit; + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java index 79b0b19..8fd8a43 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java @@ -1,144 +1,144 @@ /* - * Fernflower - The Analytical Java Decompiler - * http://www.reversed-java.com + * Copyright 2000-2014 JetBrains s.r.o. * - * (C) 2008 - 2010, Stiver + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This software is NEITHER public domain NOR free software - * as per GNU License. See license.txt for more details. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This software is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.jetbrains.java.decompiler.modules.decompiler.stats; -import java.util.Arrays; -import java.util.List; - import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.modules.decompiler.DecHelper; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; import org.jetbrains.java.decompiler.util.InterpreterUtil; +import java.util.Arrays; +import java.util.List; + public class SequenceStatement extends Statement { - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - private SequenceStatement() { - type = Statement.TYPE_SEQUENCE; - } - - public SequenceStatement(List<Statement> lst) { - - this(); - - lastBasicType = lst.get(lst.size()-1).getLastBasicType(); - - for(Statement st: lst) { - stats.addWithKey(st, st.id); - } - - first = stats.get(0); - } - - private SequenceStatement(Statement head, Statement tail) { - - this(Arrays.asList(new Statement[] {head, tail})); - - List<StatEdge> lstSuccs = tail.getSuccessorEdges(STATEDGE_DIRECT_ALL); - if(!lstSuccs.isEmpty()) { - StatEdge edge = lstSuccs.get(0); - - if(edge.getType() == StatEdge.TYPE_REGULAR && edge.getDestination() != head) { - post = edge.getDestination(); - } - } - } - - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public static Statement isHead2Block(Statement head) { - - if(head.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) { - return null; - } - - // at most one outgoing edge - StatEdge edge = null; - List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL); - if(!lstSuccs.isEmpty()) { - edge = lstSuccs.get(0); - } - - if(edge != null && edge.getType() == StatEdge.TYPE_REGULAR) { - Statement stat = edge.getDestination(); - - if(stat != head && stat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size() == 1 - && !stat.isMonitorEnter()) { - - if(stat.getLastBasicType() == Statement.LASTBASICTYPE_GENERAL) { - if(DecHelper.checkStatementExceptions(Arrays.asList(new Statement[] {head, stat}))) { - return new SequenceStatement(head, stat); - } - } - } - } - - return null; - } - - public String toJava(int indent) { - - StringBuilder buf = new StringBuilder(); - - String indstr = null; - boolean islabeled = isLabeled(); - - String new_line_separator = DecompilerContext.getNewLineSeparator(); - - buf.append(ExprProcessor.listToJava(varDefinitions, indent)); - - if(islabeled) { - indstr = InterpreterUtil.getIndentString(indent); - indent++; - buf.append(indstr+"label"+this.id+": {" + new_line_separator); - } - - boolean notempty = false; - - for(int i=0;i<stats.size();i++) { - - Statement st = stats.get(i); - - if(i>0 && notempty) { - buf.append(new_line_separator); - } - - String str = ExprProcessor.jmpWrapper(st, indent, false); - buf.append(str); - - notempty = (str.trim().length() > 0); - } - - if(islabeled) { - buf.append(indstr+"}" + new_line_separator); - } - - return buf.toString(); - } - - public Statement getSimpleCopy() { - return new SequenceStatement(); - } - + + // ***************************************************************************** + // constructors + // ***************************************************************************** + + private SequenceStatement() { + type = Statement.TYPE_SEQUENCE; + } + + public SequenceStatement(List<Statement> lst) { + + this(); + + lastBasicType = lst.get(lst.size() - 1).getLastBasicType(); + + for (Statement st : lst) { + stats.addWithKey(st, st.id); + } + + first = stats.get(0); + } + + private SequenceStatement(Statement head, Statement tail) { + + this(Arrays.asList(new Statement[]{head, tail})); + + List<StatEdge> lstSuccs = tail.getSuccessorEdges(STATEDGE_DIRECT_ALL); + if (!lstSuccs.isEmpty()) { + StatEdge edge = lstSuccs.get(0); + + if (edge.getType() == StatEdge.TYPE_REGULAR && edge.getDestination() != head) { + post = edge.getDestination(); + } + } + } + + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public static Statement isHead2Block(Statement head) { + + if (head.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) { + return null; + } + + // at most one outgoing edge + StatEdge edge = null; + List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL); + if (!lstSuccs.isEmpty()) { + edge = lstSuccs.get(0); + } + + if (edge != null && edge.getType() == StatEdge.TYPE_REGULAR) { + Statement stat = edge.getDestination(); + + if (stat != head && stat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size() == 1 + && !stat.isMonitorEnter()) { + + if (stat.getLastBasicType() == Statement.LASTBASICTYPE_GENERAL) { + if (DecHelper.checkStatementExceptions(Arrays.asList(new Statement[]{head, stat}))) { + return new SequenceStatement(head, stat); + } + } + } + } + + return null; + } + + public String toJava(int indent) { + + StringBuilder buf = new StringBuilder(); + + String indstr = null; + boolean islabeled = isLabeled(); + + String new_line_separator = DecompilerContext.getNewLineSeparator(); + + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); + + if (islabeled) { + indstr = InterpreterUtil.getIndentString(indent); + indent++; + buf.append(indstr + "label" + this.id + ": {" + new_line_separator); + } + + boolean notempty = false; + + for (int i = 0; i < stats.size(); i++) { + + Statement st = stats.get(i); + + if (i > 0 && notempty) { + buf.append(new_line_separator); + } + + String str = ExprProcessor.jmpWrapper(st, indent, false); + buf.append(str); + + notempty = (str.trim().length() > 0); + } + + if (islabeled) { + buf.append(indstr + "}" + new_line_separator); + } + + return buf.toString(); + } + + public Statement getSimpleCopy() { + return new SequenceStatement(); + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java index 2f64035..aceb2b8 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java @@ -1,27 +1,20 @@ /* - * Fernflower - The Analytical Java Decompiler - * http://www.reversed-java.com + * Copyright 2000-2014 JetBrains s.r.o. * - * (C) 2008 - 2010, Stiver + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This software is NEITHER public domain NOR free software - * as per GNU License. See license.txt for more details. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This software is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.jetbrains.java.decompiler.modules.decompiler.stats; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.code.InstructionSequence; import org.jetbrains.java.decompiler.main.DecompilerContext; @@ -32,840 +25,848 @@ import org.jetbrains.java.decompiler.modules.decompiler.StrongConnectivityHelper import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; import org.jetbrains.java.decompiler.util.VBStyleCollection; +import java.util.*; + public class Statement { - - public static final int STATEDGE_ALL = 1 << 31; - public static final int STATEDGE_DIRECT_ALL = 1 << 30; - - public static final int DIRECTION_BACKWARD = 0; - public static final int DIRECTION_FORWARD = 1; - - public static final int TYPE_GENERAL = 0; - public static final int TYPE_IF = 2; - public static final int TYPE_DO = 5; - public static final int TYPE_SWITCH = 6; - public static final int TYPE_TRYCATCH = 7; - public static final int TYPE_BASICBLOCK = 8; - public static final int TYPE_FINALLY = 9; - public static final int TYPE_SYNCRONIZED = 10; - public static final int TYPE_PLACEHOLDER = 11; - public static final int TYPE_CATCHALL = 12; - public static final int TYPE_ROOT = 13; - public static final int TYPE_DUMMYEXIT = 14; - public static final int TYPE_SEQUENCE = 15; - - - public static final int LASTBASICTYPE_IF = 0; - public static final int LASTBASICTYPE_SWITCH = 1; - public static final int LASTBASICTYPE_GENERAL = 2; - - - // ***************************************************************************** - // public fields - // ***************************************************************************** - - public int type; - - public Integer id; - - // ***************************************************************************** - // private fields - // ***************************************************************************** - - private Map<Integer, List<StatEdge>> mapSuccEdges = new HashMap<Integer, List<StatEdge>>(); - private Map<Integer, List<StatEdge>> mapPredEdges = new HashMap<Integer, List<StatEdge>>(); - - private Map<Integer, List<Statement>> mapSuccStates = new HashMap<Integer, List<Statement>>(); - private Map<Integer, List<Statement>> mapPredStates = new HashMap<Integer, List<Statement>>(); - - // statement as graph - protected VBStyleCollection<Statement, Integer> stats = new VBStyleCollection<Statement, Integer>(); - - protected Statement parent; - - protected Statement first; - - protected List<Exprent> exprents; - - protected HashSet<StatEdge> labelEdges = new HashSet<StatEdge>(); - - protected List<Exprent> varDefinitions = new ArrayList<Exprent>(); - - // copied statement, s. deobfuscating of irreducible CFGs - private boolean copied = false; - - // relevant for the first stage of processing only - // set to null after initializing of the statement structure - - protected Statement post; - - protected int lastBasicType = LASTBASICTYPE_GENERAL; - - protected boolean isMonitorEnter; - - protected boolean containsMonitorExit; - - protected HashSet<Statement> continueSet = new HashSet<Statement>(); - - // ***************************************************************************** - // initializers - // ***************************************************************************** - - { - // set statement id - id = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER); - } - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public void clearTempInformation() { - - post = null; - continueSet = null; - - copied = false; - // FIXME: used in FlattenStatementsHelper.flattenStatement()! check and remove - //lastBasicType = LASTBASICTYPE_GENERAL; - isMonitorEnter = false;; - containsMonitorExit = false; - - for(Map<Integer, List<StatEdge>> map : new Map[]{mapSuccEdges, mapPredEdges}) { - map.remove(StatEdge.TYPE_EXCEPTION); - - List<StatEdge> lst = map.get(STATEDGE_DIRECT_ALL); - if(lst != null) { - map.put(STATEDGE_ALL, new ArrayList<StatEdge>(lst)); - } else { - map.remove(STATEDGE_ALL); - } - } - - for(Map<Integer, List<Statement>> map : new Map[]{mapSuccStates, mapPredStates}) { - map.remove(StatEdge.TYPE_EXCEPTION); - - List<Statement> lst = map.get(STATEDGE_DIRECT_ALL); - if(lst != null) { - map.put(STATEDGE_ALL, new ArrayList<Statement>(lst)); - } else { - map.remove(STATEDGE_ALL); - } - } - - } - - public void collapseNodesToStatement(Statement stat) { - - Statement head = stat.getFirst(); - Statement post = stat.getPost(); - - VBStyleCollection<Statement, Integer> setNodes = stat.getStats(); - - // post edges - if(post != null) { - for(StatEdge edge : post.getEdges(STATEDGE_DIRECT_ALL, DIRECTION_BACKWARD)) { - if(stat.containsStatementStrict(edge.getSource())) { - edge.getSource().changeEdgeType(DIRECTION_FORWARD, edge, StatEdge.TYPE_BREAK); - stat.addLabeledEdge(edge); - } - } - } - - // regular head edges - for(StatEdge prededge : head.getAllPredecessorEdges()) { - - if(prededge.getType() != StatEdge.TYPE_EXCEPTION && - stat.containsStatementStrict(prededge.getSource())) { - prededge.getSource().changeEdgeType(DIRECTION_FORWARD, prededge, StatEdge.TYPE_CONTINUE); - stat.addLabeledEdge(prededge); - } - - head.removePredecessor(prededge); - prededge.getSource().changeEdgeNode(DIRECTION_FORWARD, prededge, stat); - stat.addPredecessor(prededge); - } - - if(setNodes.containsKey(first.id)) { - first = stat; - } - - // exception edges - Set<Statement> setHandlers = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)); - for(Statement node : setNodes) { - setHandlers.retainAll(node.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)); - } - - if(!setHandlers.isEmpty()) { - - for(StatEdge edge : head.getEdges(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)) { - Statement handler = edge.getDestination(); - - if(setHandlers.contains(handler)) { - if(!setNodes.containsKey(handler.id)) { - stat.addSuccessor(new StatEdge(stat, handler, edge.getExceptions())); - } - } - } - - for(Statement node : setNodes) { - for(StatEdge edge : node.getEdges(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)) { - if(setHandlers.contains(edge.getDestination())) { - node.removeSuccessor(edge); - } - } - } - } - - if(post!=null && !stat.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD).contains(post)) { // TODO: second condition redundant? - stat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, stat, post)); - } - - - // adjust statement collection - for(Statement st: setNodes) { - stats.removeWithKey(st.id); - } - - stats.addWithKey(stat, stat.id); - - stat.setAllParent(); - stat.setParent(this); - - stat.buildContinueSet(); - // monitorenter and monitorexit - stat.buildMonitorFlags(); - - if(stat.type == Statement.TYPE_SWITCH) { - // special case switch, sorting leaf nodes - ((SwitchStatement)stat).sortEdgesAndNodes(); - } - - } - - public void setAllParent() { - for(Statement st: stats) { - st.setParent(this); - } - } - - public void addLabeledEdge(StatEdge edge) { - - if(edge.closure != null) { - edge.closure.getLabelEdges().remove(edge); - } - edge.closure = this; - this.getLabelEdges().add(edge); - } - - private void addEdgeDirectInternal(int direction, StatEdge edge, int edgetype) { - - Map<Integer, List<StatEdge>> mapEdges = direction==DIRECTION_BACKWARD?mapPredEdges:mapSuccEdges; - Map<Integer, List<Statement>> mapStates = direction==DIRECTION_BACKWARD?mapPredStates:mapSuccStates; - - List<StatEdge> lst = mapEdges.get(edgetype); - if(lst == null) { - mapEdges.put(edgetype, lst = new ArrayList<StatEdge>()); - } - lst.add(edge); - - List<Statement> lstStates = mapStates.get(edgetype); - if(lstStates == null) { - mapStates.put(edgetype, lstStates = new ArrayList<Statement>()); - } - lstStates.add(direction==DIRECTION_BACKWARD?edge.getSource():edge.getDestination()); - } - - private void addEdgeInternal(int direction, StatEdge edge) { - - int type = edge.getType(); - - int[] arrtypes; - if(type == StatEdge.TYPE_EXCEPTION) { - arrtypes = new int[] {STATEDGE_ALL, StatEdge.TYPE_EXCEPTION}; - } else { - arrtypes = new int[] {STATEDGE_ALL, STATEDGE_DIRECT_ALL, type}; - } - - for(int edgetype : arrtypes) { - addEdgeDirectInternal(direction, edge, edgetype); - } - - } - - private void removeEdgeDirectInternal(int direction, StatEdge edge, int edgetype) { - - Map<Integer, List<StatEdge>> mapEdges = direction==DIRECTION_BACKWARD?mapPredEdges:mapSuccEdges; - Map<Integer, List<Statement>> mapStates = direction==DIRECTION_BACKWARD?mapPredStates:mapSuccStates; - - List<StatEdge> lst = mapEdges.get(edgetype); - if(lst != null) { - int index = lst.indexOf(edge); - if(index >= 0) { - lst.remove(index); - mapStates.get(edgetype).remove(index); - } - } - - } - - private void removeEdgeInternal(int direction, StatEdge edge) { - - int type = edge.getType(); - - int[] arrtypes; - if(type == StatEdge.TYPE_EXCEPTION) { - arrtypes = new int[] {STATEDGE_ALL, StatEdge.TYPE_EXCEPTION}; - } else { - arrtypes = new int[] {STATEDGE_ALL, STATEDGE_DIRECT_ALL, type}; - } - - for(int edgetype : arrtypes) { - removeEdgeDirectInternal(direction, edge, edgetype); - } - - } - - public void addPredecessor(StatEdge edge) { - addEdgeInternal(DIRECTION_BACKWARD, edge); - } - - public void removePredecessor(StatEdge edge) { - - if(edge == null) { // FIXME: redundant? - return; - } - - removeEdgeInternal(DIRECTION_BACKWARD, edge); - } - - public void addSuccessor(StatEdge edge) { - addEdgeInternal(DIRECTION_FORWARD, edge); - - if(edge.closure != null) { - edge.closure.getLabelEdges().add(edge); - } - - edge.getDestination().addPredecessor(edge); - } - - public void removeSuccessor(StatEdge edge) { - - if(edge == null) { - return; - } - - removeEdgeInternal(DIRECTION_FORWARD, edge); - - if(edge.closure != null) { - edge.closure.getLabelEdges().remove(edge); - } - - if(edge.getDestination() != null) { // TODO: redundant? - edge.getDestination().removePredecessor(edge); - } - } - - // TODO: make obsolete and remove - public void removeAllSuccessors(Statement stat) { - - if(stat == null) { - return; - } - - for(StatEdge edge : getAllSuccessorEdges()) { - if(edge.getDestination() == stat) { - removeSuccessor(edge); - } - } - } - - public HashSet<Statement> buildContinueSet() { - continueSet.clear(); - - for(Statement st: stats) { - continueSet.addAll(st.buildContinueSet()); - if(st != first) { - continueSet.remove(st.getBasichead()); - } - } - - for(StatEdge edge: getEdges(StatEdge.TYPE_CONTINUE, DIRECTION_FORWARD)) { - continueSet.add(edge.getDestination().getBasichead()); - } - - if(type == Statement.TYPE_DO) { - continueSet.remove(first.getBasichead()); - } - - return continueSet; - } - - public void buildMonitorFlags() { - - for(Statement st: stats) { - st.buildMonitorFlags(); - } - - switch(type) { - case TYPE_BASICBLOCK: - BasicBlockStatement bblock = (BasicBlockStatement)this; - InstructionSequence seq = bblock.getBlock().getSeq(); - - if(seq!=null && seq.length()>0) { - for(int i=0;i<seq.length();i++) { - if(seq.getInstr(i).opcode == CodeConstants.opc_monitorexit) { - containsMonitorExit = true; - break; - } - } - isMonitorEnter = (seq.getLastInstr().opcode == CodeConstants.opc_monitorenter); - } - break; - case TYPE_SEQUENCE: - case TYPE_IF: - containsMonitorExit = false; - for(Statement st: stats) { - containsMonitorExit |= st.isContainsMonitorExit(); - } - - break; - case TYPE_SYNCRONIZED: - case TYPE_ROOT: - case TYPE_GENERAL: - break; - default: - containsMonitorExit = false; - for(Statement st: stats) { - containsMonitorExit |= st.isContainsMonitorExit(); - } - } - } - - - public List<Statement> getReversePostOrderList() { - return getReversePostOrderList(first); - } - - public List<Statement> getReversePostOrderList(Statement stat) { - List<Statement> res = new ArrayList<Statement>(); - - addToReversePostOrderListIterative(stat, res); - - return res; - } - - public List<Statement> getPostReversePostOrderList() { - return getPostReversePostOrderList(null); - } - - public List<Statement> getPostReversePostOrderList(List<Statement> lstexits) { - - List<Statement> res = new ArrayList<Statement>(); - - if(lstexits == null) { - StrongConnectivityHelper schelper = new StrongConnectivityHelper(this); - lstexits = StrongConnectivityHelper.getExitReps(schelper.getComponents()); - } - - HashSet<Statement> setVisited = new HashSet<Statement>(); - - for(Statement exit : lstexits) { - addToPostReversePostOrderList(exit, res, setVisited); - } - - if(res.size() != stats.size()) { - DecompilerContext.getLogger().writeMessage("computing post reverse post order failed!", IFernflowerLogger.ERROR); - - throw new RuntimeException("parsing failure!"); - } - - return res; - } - - public boolean containsStatement(Statement stat) { - return this == stat || containsStatementStrict(stat); - } - - public boolean containsStatementStrict(Statement stat) { - - if(stats.contains(stat)) { - return true; - } - - for(int i=0;i<stats.size();i++) { - if(stats.get(i).containsStatementStrict(stat)) { - return true; - } - } - - return false; - } - - // to be overwritten - public String toJava() { - return toJava(0); - } - - public String toJava(int indent) { - throw new RuntimeException("not implemented"); - } - - // TODO: make obsolete and remove - public List<Object> getSequentialObjects() { - return new ArrayList<Object>(stats); - } - - public void initExprents() { - ; // do nothing - } - - public void replaceExprent(Exprent oldexpr, Exprent newexpr) { - ; // do nothing - } - - public Statement getSimpleCopy() { - throw new RuntimeException("not implemented"); - } - - public void initSimpleCopy() { - if(!stats.isEmpty()) { - first = stats.get(0); - } - } - - public void replaceStatement(Statement oldstat, Statement newstat) { - - for(StatEdge edge : oldstat.getAllPredecessorEdges()) { - oldstat.removePredecessor(edge); - edge.getSource().changeEdgeNode(DIRECTION_FORWARD, edge, newstat); - newstat.addPredecessor(edge); - } - - for(StatEdge edge : oldstat.getAllSuccessorEdges()) { - oldstat.removeSuccessor(edge); - edge.setSource(newstat); - newstat.addSuccessor(edge); - } - - int statindex = stats.getIndexByKey(oldstat.id); - stats.removeWithKey(oldstat.id); - stats.addWithKeyAndIndex(statindex, newstat, newstat.id); - - newstat.setParent(this); - newstat.post = oldstat.post; - - if(first == oldstat) { - first = newstat; - } - - List<StatEdge> lst = new ArrayList<StatEdge>(oldstat.getLabelEdges()); - - for(int i=lst.size()-1;i>=0;i--) { - StatEdge edge = lst.get(i); - if(edge.getSource() != newstat) { - newstat.addLabeledEdge(edge); - } else { - if(this == edge.getDestination() || this.containsStatementStrict(edge.getDestination())) { - edge.closure = null; - } else { - this.addLabeledEdge(edge); - } - } - } - - oldstat.getLabelEdges().clear(); - } - - - // ***************************************************************************** - // private methods - // ***************************************************************************** - - private void addToReversePostOrderListIterative(Statement root, List<Statement> lst) { - - LinkedList<Statement> stackNode = new LinkedList<Statement>(); - LinkedList<Integer> stackIndex = new LinkedList<Integer>(); - HashSet<Statement> setVisited = new HashSet<Statement>(); - - stackNode.add(root); - stackIndex.add(0); - - while(!stackNode.isEmpty()) { - - Statement node = stackNode.getLast(); - int index = stackIndex.removeLast(); - - setVisited.add(node); - - List<StatEdge> lstEdges = node.getAllSuccessorEdges(); - - for(;index<lstEdges.size();index++) { - StatEdge edge = lstEdges.get(index); - Statement succ = edge.getDestination(); - - if(!setVisited.contains(succ) && - (edge.getType() == StatEdge.TYPE_REGULAR || edge.getType() == StatEdge.TYPE_EXCEPTION)) { // TODO: edge filter? - - stackIndex.add(index+1); - - stackNode.add(succ); - stackIndex.add(0); - - break; - } - } - - if(index == lstEdges.size()) { - lst.add(0, node); - - stackNode.removeLast(); - } - } - - } - - - private void addToPostReversePostOrderList(Statement stat, List<Statement> lst, HashSet<Statement> setVisited) { - - if(setVisited.contains(stat)) { // because of not considered exception edges, s. isExitComponent. Should be rewritten, if possible. - return; - } - setVisited.add(stat); - - for(StatEdge prededge : stat.getEdges(StatEdge.TYPE_REGULAR | StatEdge.TYPE_EXCEPTION, DIRECTION_BACKWARD)) { - Statement pred = prededge.getSource(); - if(!setVisited.contains(pred)) { - addToPostReversePostOrderList(pred, lst, setVisited); - } - } - - lst.add(0, stat); - } - - // ***************************************************************************** - // getter and setter methods - // ***************************************************************************** - - public void changeEdgeNode(int direction, StatEdge edge, Statement value) { - - Map<Integer, List<StatEdge>> mapEdges = direction==DIRECTION_BACKWARD?mapPredEdges:mapSuccEdges; - Map<Integer, List<Statement>> mapStates = direction==DIRECTION_BACKWARD?mapPredStates:mapSuccStates; - - int type = edge.getType(); - - int[] arrtypes; - if(type == StatEdge.TYPE_EXCEPTION) { - arrtypes = new int[] {STATEDGE_ALL, StatEdge.TYPE_EXCEPTION}; - } else { - arrtypes = new int[] {STATEDGE_ALL, STATEDGE_DIRECT_ALL, type}; - } - - for(int edgetype : arrtypes) { - List<StatEdge> lst = mapEdges.get(edgetype); - if(lst != null) { - int index = lst.indexOf(edge); - if(index >= 0) { - mapStates.get(edgetype).set(index, value); - } - } - } - - if(direction == DIRECTION_BACKWARD) { - edge.setSource(value); - } else { - edge.setDestination(value); - } - - } - - public void changeEdgeType(int direction, StatEdge edge, int newtype) { - - int oldtype = edge.getType(); - if(oldtype == newtype) { - return; - } - - if(oldtype == StatEdge.TYPE_EXCEPTION || newtype == StatEdge.TYPE_EXCEPTION) { - throw new RuntimeException("Invalid edge type!"); - } - - removeEdgeDirectInternal(direction, edge, oldtype); - addEdgeDirectInternal(direction, edge, newtype); - - if(direction == DIRECTION_FORWARD) { - edge.getDestination().changeEdgeType(DIRECTION_BACKWARD, edge, newtype); - } - - edge.setType(newtype); - } - - - private List<StatEdge> getEdges(int type, int direction) { - - Map<Integer, List<StatEdge>> map = direction==DIRECTION_BACKWARD?mapPredEdges:mapSuccEdges; - - List<StatEdge> res; - if((type & (type -1)) == 0) { - res = map.get(type); - res = res==null?new ArrayList<StatEdge>():new ArrayList<StatEdge>(res); - } else { - res = new ArrayList<StatEdge>(); - for(int edgetype : StatEdge.TYPES) { - if((type & edgetype) != 0) { - List<StatEdge> lst = map.get(edgetype); - if(lst != null) { - res.addAll(lst); - } - } - } - } - - return res; - } - - public List<Statement> getNeighbours(int type, int direction) { - - Map<Integer, List<Statement>> map = direction==DIRECTION_BACKWARD?mapPredStates:mapSuccStates; - - List<Statement> res; - if((type & (type -1)) == 0) { - res = map.get(type); - res = res==null?new ArrayList<Statement>():new ArrayList<Statement>(res); - } else { - res = new ArrayList<Statement>(); - for(int edgetype : StatEdge.TYPES) { - if((type & edgetype) != 0) { - List<Statement> lst = map.get(edgetype); - if(lst != null) { - res.addAll(lst); - } - } - } - } - - return res; - } - - public Set<Statement> getNeighboursSet(int type, int direction) { - return new HashSet<Statement>(getNeighbours(type, direction)); - } - - public List<StatEdge> getSuccessorEdges(int type) { - return getEdges(type, DIRECTION_FORWARD); - } - - public List<StatEdge> getPredecessorEdges(int type) { - return getEdges(type, DIRECTION_BACKWARD); - } - - public List<StatEdge> getAllSuccessorEdges() { - return getEdges(STATEDGE_ALL, DIRECTION_FORWARD); - } - - public List<StatEdge> getAllPredecessorEdges() { - return getEdges(STATEDGE_ALL, DIRECTION_BACKWARD); - } - - public Statement getFirst() { - return first; - } - - public void setFirst(Statement first) { - this.first = first; - } - - public Statement getPost() { - return post; - } - - public void setPost(Statement post) { - this.post = post; - } - - public VBStyleCollection<Statement, Integer> getStats() { - return stats; - } - - public int getLastBasicType() { - return lastBasicType; - } - - public HashSet<Statement> getContinueSet() { - return continueSet; - } - - public boolean isContainsMonitorExit() { - return containsMonitorExit; - } - - public boolean isMonitorEnter() { - return isMonitorEnter; - } - - public BasicBlockStatement getBasichead() { - if(type == Statement.TYPE_BASICBLOCK) { - return (BasicBlockStatement)this; - } else { - return first.getBasichead(); - } - } - - public boolean isLabeled() { - - for(StatEdge edge: labelEdges) { - if(edge.labeled && edge.explicit) { // FIXME: consistent setting - return true; - } - } - return false; - } - - public boolean hasBasicSuccEdge() { - boolean res = type == Statement.TYPE_BASICBLOCK || (type == Statement.TYPE_IF && - ((IfStatement)this).iftype == IfStatement.IFTYPE_IF) || - (type == Statement.TYPE_DO && ((DoStatement)this).getLooptype() != DoStatement.LOOP_DO); - - // FIXME: default switch - - return res; - } - - - public Statement getParent() { - return parent; - } - - public void setParent(Statement parent) { - this.parent = parent; - } - - public HashSet<StatEdge> getLabelEdges() { // FIXME: why HashSet? - return labelEdges; - } - - public List<Exprent> getVarDefinitions() { - return varDefinitions; - } - - public List<Exprent> getExprents() { - return exprents; - } - - public void setExprents(List<Exprent> exprents) { - this.exprents = exprents; - } - - public boolean isCopied() { - return copied; - } - - public void setCopied(boolean copied) { - this.copied = copied; - } - - // helper methods - public String toString() { - return id.toString(); - } + + public static final int STATEDGE_ALL = 1 << 31; + public static final int STATEDGE_DIRECT_ALL = 1 << 30; + + public static final int DIRECTION_BACKWARD = 0; + public static final int DIRECTION_FORWARD = 1; + + public static final int TYPE_GENERAL = 0; + public static final int TYPE_IF = 2; + public static final int TYPE_DO = 5; + public static final int TYPE_SWITCH = 6; + public static final int TYPE_TRYCATCH = 7; + public static final int TYPE_BASICBLOCK = 8; + public static final int TYPE_FINALLY = 9; + public static final int TYPE_SYNCRONIZED = 10; + public static final int TYPE_PLACEHOLDER = 11; + public static final int TYPE_CATCHALL = 12; + public static final int TYPE_ROOT = 13; + public static final int TYPE_DUMMYEXIT = 14; + public static final int TYPE_SEQUENCE = 15; + + + public static final int LASTBASICTYPE_IF = 0; + public static final int LASTBASICTYPE_SWITCH = 1; + public static final int LASTBASICTYPE_GENERAL = 2; + + + // ***************************************************************************** + // public fields + // ***************************************************************************** + + public int type; + + public Integer id; + + // ***************************************************************************** + // private fields + // ***************************************************************************** + + private Map<Integer, List<StatEdge>> mapSuccEdges = new HashMap<Integer, List<StatEdge>>(); + private Map<Integer, List<StatEdge>> mapPredEdges = new HashMap<Integer, List<StatEdge>>(); + + private Map<Integer, List<Statement>> mapSuccStates = new HashMap<Integer, List<Statement>>(); + private Map<Integer, List<Statement>> mapPredStates = new HashMap<Integer, List<Statement>>(); + + // statement as graph + protected VBStyleCollection<Statement, Integer> stats = new VBStyleCollection<Statement, Integer>(); + + protected Statement parent; + + protected Statement first; + + protected List<Exprent> exprents; + + protected HashSet<StatEdge> labelEdges = new HashSet<StatEdge>(); + + protected List<Exprent> varDefinitions = new ArrayList<Exprent>(); + + // copied statement, s. deobfuscating of irreducible CFGs + private boolean copied = false; + + // relevant for the first stage of processing only + // set to null after initializing of the statement structure + + protected Statement post; + + protected int lastBasicType = LASTBASICTYPE_GENERAL; + + protected boolean isMonitorEnter; + + protected boolean containsMonitorExit; + + protected HashSet<Statement> continueSet = new HashSet<Statement>(); + + // ***************************************************************************** + // initializers + // ***************************************************************************** + + { + // set statement id + id = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER); + } + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public void clearTempInformation() { + + post = null; + continueSet = null; + + copied = false; + // FIXME: used in FlattenStatementsHelper.flattenStatement()! check and remove + //lastBasicType = LASTBASICTYPE_GENERAL; + isMonitorEnter = false; + ; + containsMonitorExit = false; + + for (Map<Integer, List<StatEdge>> map : new Map[]{mapSuccEdges, mapPredEdges}) { + map.remove(StatEdge.TYPE_EXCEPTION); + + List<StatEdge> lst = map.get(STATEDGE_DIRECT_ALL); + if (lst != null) { + map.put(STATEDGE_ALL, new ArrayList<StatEdge>(lst)); + } + else { + map.remove(STATEDGE_ALL); + } + } + + for (Map<Integer, List<Statement>> map : new Map[]{mapSuccStates, mapPredStates}) { + map.remove(StatEdge.TYPE_EXCEPTION); + + List<Statement> lst = map.get(STATEDGE_DIRECT_ALL); + if (lst != null) { + map.put(STATEDGE_ALL, new ArrayList<Statement>(lst)); + } + else { + map.remove(STATEDGE_ALL); + } + } + } + + public void collapseNodesToStatement(Statement stat) { + + Statement head = stat.getFirst(); + Statement post = stat.getPost(); + + VBStyleCollection<Statement, Integer> setNodes = stat.getStats(); + + // post edges + if (post != null) { + for (StatEdge edge : post.getEdges(STATEDGE_DIRECT_ALL, DIRECTION_BACKWARD)) { + if (stat.containsStatementStrict(edge.getSource())) { + edge.getSource().changeEdgeType(DIRECTION_FORWARD, edge, StatEdge.TYPE_BREAK); + stat.addLabeledEdge(edge); + } + } + } + + // regular head edges + for (StatEdge prededge : head.getAllPredecessorEdges()) { + + if (prededge.getType() != StatEdge.TYPE_EXCEPTION && + stat.containsStatementStrict(prededge.getSource())) { + prededge.getSource().changeEdgeType(DIRECTION_FORWARD, prededge, StatEdge.TYPE_CONTINUE); + stat.addLabeledEdge(prededge); + } + + head.removePredecessor(prededge); + prededge.getSource().changeEdgeNode(DIRECTION_FORWARD, prededge, stat); + stat.addPredecessor(prededge); + } + + if (setNodes.containsKey(first.id)) { + first = stat; + } + + // exception edges + Set<Statement> setHandlers = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)); + for (Statement node : setNodes) { + setHandlers.retainAll(node.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)); + } + + if (!setHandlers.isEmpty()) { + + for (StatEdge edge : head.getEdges(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)) { + Statement handler = edge.getDestination(); + + if (setHandlers.contains(handler)) { + if (!setNodes.containsKey(handler.id)) { + stat.addSuccessor(new StatEdge(stat, handler, edge.getExceptions())); + } + } + } + + for (Statement node : setNodes) { + for (StatEdge edge : node.getEdges(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)) { + if (setHandlers.contains(edge.getDestination())) { + node.removeSuccessor(edge); + } + } + } + } + + if (post != null && + !stat.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD).contains(post)) { // TODO: second condition redundant? + stat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, stat, post)); + } + + + // adjust statement collection + for (Statement st : setNodes) { + stats.removeWithKey(st.id); + } + + stats.addWithKey(stat, stat.id); + + stat.setAllParent(); + stat.setParent(this); + + stat.buildContinueSet(); + // monitorenter and monitorexit + stat.buildMonitorFlags(); + + if (stat.type == Statement.TYPE_SWITCH) { + // special case switch, sorting leaf nodes + ((SwitchStatement)stat).sortEdgesAndNodes(); + } + } + + public void setAllParent() { + for (Statement st : stats) { + st.setParent(this); + } + } + + public void addLabeledEdge(StatEdge edge) { + + if (edge.closure != null) { + edge.closure.getLabelEdges().remove(edge); + } + edge.closure = this; + this.getLabelEdges().add(edge); + } + + private void addEdgeDirectInternal(int direction, StatEdge edge, int edgetype) { + + Map<Integer, List<StatEdge>> mapEdges = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges; + Map<Integer, List<Statement>> mapStates = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates; + + List<StatEdge> lst = mapEdges.get(edgetype); + if (lst == null) { + mapEdges.put(edgetype, lst = new ArrayList<StatEdge>()); + } + lst.add(edge); + + List<Statement> lstStates = mapStates.get(edgetype); + if (lstStates == null) { + mapStates.put(edgetype, lstStates = new ArrayList<Statement>()); + } + lstStates.add(direction == DIRECTION_BACKWARD ? edge.getSource() : edge.getDestination()); + } + + private void addEdgeInternal(int direction, StatEdge edge) { + + int type = edge.getType(); + + int[] arrtypes; + if (type == StatEdge.TYPE_EXCEPTION) { + arrtypes = new int[]{STATEDGE_ALL, StatEdge.TYPE_EXCEPTION}; + } + else { + arrtypes = new int[]{STATEDGE_ALL, STATEDGE_DIRECT_ALL, type}; + } + + for (int edgetype : arrtypes) { + addEdgeDirectInternal(direction, edge, edgetype); + } + } + + private void removeEdgeDirectInternal(int direction, StatEdge edge, int edgetype) { + + Map<Integer, List<StatEdge>> mapEdges = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges; + Map<Integer, List<Statement>> mapStates = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates; + + List<StatEdge> lst = mapEdges.get(edgetype); + if (lst != null) { + int index = lst.indexOf(edge); + if (index >= 0) { + lst.remove(index); + mapStates.get(edgetype).remove(index); + } + } + } + + private void removeEdgeInternal(int direction, StatEdge edge) { + + int type = edge.getType(); + + int[] arrtypes; + if (type == StatEdge.TYPE_EXCEPTION) { + arrtypes = new int[]{STATEDGE_ALL, StatEdge.TYPE_EXCEPTION}; + } + else { + arrtypes = new int[]{STATEDGE_ALL, STATEDGE_DIRECT_ALL, type}; + } + + for (int edgetype : arrtypes) { + removeEdgeDirectInternal(direction, edge, edgetype); + } + } + + public void addPredecessor(StatEdge edge) { + addEdgeInternal(DIRECTION_BACKWARD, edge); + } + + public void removePredecessor(StatEdge edge) { + + if (edge == null) { // FIXME: redundant? + return; + } + + removeEdgeInternal(DIRECTION_BACKWARD, edge); + } + + public void addSuccessor(StatEdge edge) { + addEdgeInternal(DIRECTION_FORWARD, edge); + + if (edge.closure != null) { + edge.closure.getLabelEdges().add(edge); + } + + edge.getDestination().addPredecessor(edge); + } + + public void removeSuccessor(StatEdge edge) { + + if (edge == null) { + return; + } + + removeEdgeInternal(DIRECTION_FORWARD, edge); + + if (edge.closure != null) { + edge.closure.getLabelEdges().remove(edge); + } + + if (edge.getDestination() != null) { // TODO: redundant? + edge.getDestination().removePredecessor(edge); + } + } + + // TODO: make obsolete and remove + public void removeAllSuccessors(Statement stat) { + + if (stat == null) { + return; + } + + for (StatEdge edge : getAllSuccessorEdges()) { + if (edge.getDestination() == stat) { + removeSuccessor(edge); + } + } + } + + public HashSet<Statement> buildContinueSet() { + continueSet.clear(); + + for (Statement st : stats) { + continueSet.addAll(st.buildContinueSet()); + if (st != first) { + continueSet.remove(st.getBasichead()); + } + } + + for (StatEdge edge : getEdges(StatEdge.TYPE_CONTINUE, DIRECTION_FORWARD)) { + continueSet.add(edge.getDestination().getBasichead()); + } + + if (type == Statement.TYPE_DO) { + continueSet.remove(first.getBasichead()); + } + + return continueSet; + } + + public void buildMonitorFlags() { + + for (Statement st : stats) { + st.buildMonitorFlags(); + } + + switch (type) { + case TYPE_BASICBLOCK: + BasicBlockStatement bblock = (BasicBlockStatement)this; + InstructionSequence seq = bblock.getBlock().getSeq(); + + if (seq != null && seq.length() > 0) { + for (int i = 0; i < seq.length(); i++) { + if (seq.getInstr(i).opcode == CodeConstants.opc_monitorexit) { + containsMonitorExit = true; + break; + } + } + isMonitorEnter = (seq.getLastInstr().opcode == CodeConstants.opc_monitorenter); + } + break; + case TYPE_SEQUENCE: + case TYPE_IF: + containsMonitorExit = false; + for (Statement st : stats) { + containsMonitorExit |= st.isContainsMonitorExit(); + } + + break; + case TYPE_SYNCRONIZED: + case TYPE_ROOT: + case TYPE_GENERAL: + break; + default: + containsMonitorExit = false; + for (Statement st : stats) { + containsMonitorExit |= st.isContainsMonitorExit(); + } + } + } + + + public List<Statement> getReversePostOrderList() { + return getReversePostOrderList(first); + } + + public List<Statement> getReversePostOrderList(Statement stat) { + List<Statement> res = new ArrayList<Statement>(); + + addToReversePostOrderListIterative(stat, res); + + return res; + } + + public List<Statement> getPostReversePostOrderList() { + return getPostReversePostOrderList(null); + } + + public List<Statement> getPostReversePostOrderList(List<Statement> lstexits) { + + List<Statement> res = new ArrayList<Statement>(); + + if (lstexits == null) { + StrongConnectivityHelper schelper = new StrongConnectivityHelper(this); + lstexits = StrongConnectivityHelper.getExitReps(schelper.getComponents()); + } + + HashSet<Statement> setVisited = new HashSet<Statement>(); + + for (Statement exit : lstexits) { + addToPostReversePostOrderList(exit, res, setVisited); + } + + if (res.size() != stats.size()) { + DecompilerContext.getLogger().writeMessage("computing post reverse post order failed!", IFernflowerLogger.ERROR); + + throw new RuntimeException("parsing failure!"); + } + + return res; + } + + public boolean containsStatement(Statement stat) { + return this == stat || containsStatementStrict(stat); + } + + public boolean containsStatementStrict(Statement stat) { + + if (stats.contains(stat)) { + return true; + } + + for (int i = 0; i < stats.size(); i++) { + if (stats.get(i).containsStatementStrict(stat)) { + return true; + } + } + + return false; + } + + // to be overwritten + public String toJava() { + return toJava(0); + } + + public String toJava(int indent) { + throw new RuntimeException("not implemented"); + } + + // TODO: make obsolete and remove + public List<Object> getSequentialObjects() { + return new ArrayList<Object>(stats); + } + + public void initExprents() { + ; // do nothing + } + + public void replaceExprent(Exprent oldexpr, Exprent newexpr) { + ; // do nothing + } + + public Statement getSimpleCopy() { + throw new RuntimeException("not implemented"); + } + + public void initSimpleCopy() { + if (!stats.isEmpty()) { + first = stats.get(0); + } + } + + public void replaceStatement(Statement oldstat, Statement newstat) { + + for (StatEdge edge : oldstat.getAllPredecessorEdges()) { + oldstat.removePredecessor(edge); + edge.getSource().changeEdgeNode(DIRECTION_FORWARD, edge, newstat); + newstat.addPredecessor(edge); + } + + for (StatEdge edge : oldstat.getAllSuccessorEdges()) { + oldstat.removeSuccessor(edge); + edge.setSource(newstat); + newstat.addSuccessor(edge); + } + + int statindex = stats.getIndexByKey(oldstat.id); + stats.removeWithKey(oldstat.id); + stats.addWithKeyAndIndex(statindex, newstat, newstat.id); + + newstat.setParent(this); + newstat.post = oldstat.post; + + if (first == oldstat) { + first = newstat; + } + + List<StatEdge> lst = new ArrayList<StatEdge>(oldstat.getLabelEdges()); + + for (int i = lst.size() - 1; i >= 0; i--) { + StatEdge edge = lst.get(i); + if (edge.getSource() != newstat) { + newstat.addLabeledEdge(edge); + } + else { + if (this == edge.getDestination() || this.containsStatementStrict(edge.getDestination())) { + edge.closure = null; + } + else { + this.addLabeledEdge(edge); + } + } + } + + oldstat.getLabelEdges().clear(); + } + + + // ***************************************************************************** + // private methods + // ***************************************************************************** + + private void addToReversePostOrderListIterative(Statement root, List<Statement> lst) { + + LinkedList<Statement> stackNode = new LinkedList<Statement>(); + LinkedList<Integer> stackIndex = new LinkedList<Integer>(); + HashSet<Statement> setVisited = new HashSet<Statement>(); + + stackNode.add(root); + stackIndex.add(0); + + while (!stackNode.isEmpty()) { + + Statement node = stackNode.getLast(); + int index = stackIndex.removeLast(); + + setVisited.add(node); + + List<StatEdge> lstEdges = node.getAllSuccessorEdges(); + + for (; index < lstEdges.size(); index++) { + StatEdge edge = lstEdges.get(index); + Statement succ = edge.getDestination(); + + if (!setVisited.contains(succ) && + (edge.getType() == StatEdge.TYPE_REGULAR || edge.getType() == StatEdge.TYPE_EXCEPTION)) { // TODO: edge filter? + + stackIndex.add(index + 1); + + stackNode.add(succ); + stackIndex.add(0); + + break; + } + } + + if (index == lstEdges.size()) { + lst.add(0, node); + + stackNode.removeLast(); + } + } + } + + + private void addToPostReversePostOrderList(Statement stat, List<Statement> lst, HashSet<Statement> setVisited) { + + if (setVisited.contains(stat)) { // because of not considered exception edges, s. isExitComponent. Should be rewritten, if possible. + return; + } + setVisited.add(stat); + + for (StatEdge prededge : stat.getEdges(StatEdge.TYPE_REGULAR | StatEdge.TYPE_EXCEPTION, DIRECTION_BACKWARD)) { + Statement pred = prededge.getSource(); + if (!setVisited.contains(pred)) { + addToPostReversePostOrderList(pred, lst, setVisited); + } + } + + lst.add(0, stat); + } + + // ***************************************************************************** + // getter and setter methods + // ***************************************************************************** + + public void changeEdgeNode(int direction, StatEdge edge, Statement value) { + + Map<Integer, List<StatEdge>> mapEdges = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges; + Map<Integer, List<Statement>> mapStates = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates; + + int type = edge.getType(); + + int[] arrtypes; + if (type == StatEdge.TYPE_EXCEPTION) { + arrtypes = new int[]{STATEDGE_ALL, StatEdge.TYPE_EXCEPTION}; + } + else { + arrtypes = new int[]{STATEDGE_ALL, STATEDGE_DIRECT_ALL, type}; + } + + for (int edgetype : arrtypes) { + List<StatEdge> lst = mapEdges.get(edgetype); + if (lst != null) { + int index = lst.indexOf(edge); + if (index >= 0) { + mapStates.get(edgetype).set(index, value); + } + } + } + + if (direction == DIRECTION_BACKWARD) { + edge.setSource(value); + } + else { + edge.setDestination(value); + } + } + + public void changeEdgeType(int direction, StatEdge edge, int newtype) { + + int oldtype = edge.getType(); + if (oldtype == newtype) { + return; + } + + if (oldtype == StatEdge.TYPE_EXCEPTION || newtype == StatEdge.TYPE_EXCEPTION) { + throw new RuntimeException("Invalid edge type!"); + } + + removeEdgeDirectInternal(direction, edge, oldtype); + addEdgeDirectInternal(direction, edge, newtype); + + if (direction == DIRECTION_FORWARD) { + edge.getDestination().changeEdgeType(DIRECTION_BACKWARD, edge, newtype); + } + + edge.setType(newtype); + } + + + private List<StatEdge> getEdges(int type, int direction) { + + Map<Integer, List<StatEdge>> map = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges; + + List<StatEdge> res; + if ((type & (type - 1)) == 0) { + res = map.get(type); + res = res == null ? new ArrayList<StatEdge>() : new ArrayList<StatEdge>(res); + } + else { + res = new ArrayList<StatEdge>(); + for (int edgetype : StatEdge.TYPES) { + if ((type & edgetype) != 0) { + List<StatEdge> lst = map.get(edgetype); + if (lst != null) { + res.addAll(lst); + } + } + } + } + + return res; + } + + public List<Statement> getNeighbours(int type, int direction) { + + Map<Integer, List<Statement>> map = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates; + + List<Statement> res; + if ((type & (type - 1)) == 0) { + res = map.get(type); + res = res == null ? new ArrayList<Statement>() : new ArrayList<Statement>(res); + } + else { + res = new ArrayList<Statement>(); + for (int edgetype : StatEdge.TYPES) { + if ((type & edgetype) != 0) { + List<Statement> lst = map.get(edgetype); + if (lst != null) { + res.addAll(lst); + } + } + } + } + + return res; + } + + public Set<Statement> getNeighboursSet(int type, int direction) { + return new HashSet<Statement>(getNeighbours(type, direction)); + } + + public List<StatEdge> getSuccessorEdges(int type) { + return getEdges(type, DIRECTION_FORWARD); + } + + public List<StatEdge> getPredecessorEdges(int type) { + return getEdges(type, DIRECTION_BACKWARD); + } + + public List<StatEdge> getAllSuccessorEdges() { + return getEdges(STATEDGE_ALL, DIRECTION_FORWARD); + } + + public List<StatEdge> getAllPredecessorEdges() { + return getEdges(STATEDGE_ALL, DIRECTION_BACKWARD); + } + + public Statement getFirst() { + return first; + } + + public void setFirst(Statement first) { + this.first = first; + } + + public Statement getPost() { + return post; + } + + public void setPost(Statement post) { + this.post = post; + } + + public VBStyleCollection<Statement, Integer> getStats() { + return stats; + } + + public int getLastBasicType() { + return lastBasicType; + } + + public HashSet<Statement> getContinueSet() { + return continueSet; + } + + public boolean isContainsMonitorExit() { + return containsMonitorExit; + } + + public boolean isMonitorEnter() { + return isMonitorEnter; + } + + public BasicBlockStatement getBasichead() { + if (type == Statement.TYPE_BASICBLOCK) { + return (BasicBlockStatement)this; + } + else { + return first.getBasichead(); + } + } + + public boolean isLabeled() { + + for (StatEdge edge : labelEdges) { + if (edge.labeled && edge.explicit) { // FIXME: consistent setting + return true; + } + } + return false; + } + + public boolean hasBasicSuccEdge() { + boolean res = type == Statement.TYPE_BASICBLOCK || (type == Statement.TYPE_IF && + ((IfStatement)this).iftype == IfStatement.IFTYPE_IF) || + (type == Statement.TYPE_DO && ((DoStatement)this).getLooptype() != DoStatement.LOOP_DO); + + // FIXME: default switch + + return res; + } + + + public Statement getParent() { + return parent; + } + + public void setParent(Statement parent) { + this.parent = parent; + } + + public HashSet<StatEdge> getLabelEdges() { // FIXME: why HashSet? + return labelEdges; + } + + public List<Exprent> getVarDefinitions() { + return varDefinitions; + } + + public List<Exprent> getExprents() { + return exprents; + } + + public void setExprents(List<Exprent> exprents) { + this.exprents = exprents; + } + + public boolean isCopied() { + return copied; + } + + public void setCopied(boolean copied) { + this.copied = copied; + } + + // helper methods + public String toString() { + return id.toString(); + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java index ec03886..379d00d 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java @@ -1,26 +1,20 @@ /* - * Fernflower - The Analytical Java Decompiler - * http://www.reversed-java.com + * Copyright 2000-2014 JetBrains s.r.o. * - * (C) 2008 - 2010, Stiver + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This software is NEITHER public domain NOR free software - * as per GNU License. See license.txt for more details. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This software is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.jetbrains.java.decompiler.modules.decompiler.stats; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import org.jetbrains.java.decompiler.code.SwitchInstruction; import org.jetbrains.java.decompiler.code.cfg.BasicBlock; import org.jetbrains.java.decompiler.main.DecompilerContext; @@ -34,337 +28,340 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.SwitchExprent; import org.jetbrains.java.decompiler.struct.gen.VarType; import org.jetbrains.java.decompiler.util.InterpreterUtil; +import java.util.*; + public class SwitchStatement extends Statement { - // ***************************************************************************** - // private fields - // ***************************************************************************** - - private List<Statement> caseStatements = new ArrayList<Statement>(); - - private List<List<StatEdge>> caseEdges = new ArrayList<List<StatEdge>>(); - - private List<List<ConstExprent>> caseValues = new ArrayList<List<ConstExprent>>(); - - private StatEdge default_edge; - - private List<Exprent> headexprent = new ArrayList<Exprent>(); - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - private SwitchStatement() { - type = TYPE_SWITCH; - - headexprent.add(null); - } - - private SwitchStatement(Statement head, Statement poststat) { - - this(); - - first = head; - stats.addWithKey(head, head.id); - - // find post node - Set<Statement> lstNodes = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_REGULAR, DIRECTION_FORWARD)); - - // cluster nodes - if(poststat != null) { - post = poststat; - lstNodes.remove(post); - } - - default_edge = head.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0); - - for(Statement st: lstNodes) { - stats.addWithKey(st, st.id); - } - - } - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public static Statement isHead(Statement head) { - - if(head.type == Statement.TYPE_BASICBLOCK && head.getLastBasicType() == Statement.LASTBASICTYPE_SWITCH) { - - List<Statement> lst = new ArrayList<Statement>(); - if(DecHelper.isChoiceStatement(head, lst)) { - Statement post = lst.remove(0); - - for(Statement st : lst) { - if(st.isMonitorEnter()) { - return null; - } - } - - if(DecHelper.checkStatementExceptions(lst)) { - return new SwitchStatement(head, post); - } - } - } - - return null; - } - - public String toJava(int indent) { - - String indstr = InterpreterUtil.getIndentString(indent); - - String new_line_separator = DecompilerContext.getNewLineSeparator(); - - StringBuilder buf = new StringBuilder(); - buf.append(ExprProcessor.listToJava(varDefinitions, indent)); - buf.append(first.toJava(indent)); - - if(isLabeled()) { - buf.append(indstr+"label"+this.id+":" + new_line_separator); - } - - buf.append(indstr+headexprent.get(0).toJava(indent)+" {" + new_line_separator); - - VarType switch_type = headexprent.get(0).getExprType(); - - for(int i=0;i<caseStatements.size();i++) { - - Statement stat = caseStatements.get(i); - List<StatEdge> edges = caseEdges.get(i); - List<ConstExprent> values = caseValues.get(i); - - for(int j=0;j<edges.size();j++) { - if(edges.get(j) == default_edge) { - buf.append(indstr+"default:" + new_line_separator); - } else { - ConstExprent value = (ConstExprent)values.get(j).copy(); - value.setConsttype(switch_type); - - buf.append(indstr+"case "+ value.toJava(indent)+":" + new_line_separator); - } - } - - buf.append(ExprProcessor.jmpWrapper(stat, indent+1, false)); - } - - buf.append(indstr+"}" + new_line_separator); - - return buf.toString(); - } - - public void initExprents() { - SwitchExprent swexpr = (SwitchExprent)first.getExprents().remove(first.getExprents().size()-1); - swexpr.setCaseValues(caseValues); - - headexprent.set(0, swexpr); - } - - public List<Object> getSequentialObjects() { - - List<Object> lst = new ArrayList<Object>(stats); - lst.add(1, headexprent.get(0)); - - return lst; - } - - public void replaceExprent(Exprent oldexpr, Exprent newexpr) { - if(headexprent.get(0) == oldexpr) { - headexprent.set(0, newexpr); - } - } - - public void replaceStatement(Statement oldstat, Statement newstat) { - - for(int i=0;i<caseStatements.size();i++) { - if(caseStatements.get(i) == oldstat) { - caseStatements.set(i, newstat); - } - } - - super.replaceStatement(oldstat, newstat); - } - - public Statement getSimpleCopy() { - return new SwitchStatement(); - } - - public void initSimpleCopy() { - first = stats.get(0); - default_edge = first.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0); - - sortEdgesAndNodes(); - } - - // ***************************************************************************** - // private methods - // ***************************************************************************** - - public void sortEdgesAndNodes() { - - HashMap<StatEdge, Integer> mapEdgeIndex = new HashMap<StatEdge, Integer>(); - - List<StatEdge> lstFirstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL); - for(int i=0;i<lstFirstSuccs.size();i++) { - mapEdgeIndex.put(lstFirstSuccs.get(i), i==0?lstFirstSuccs.size():i); - } - - // case values - BasicBlockStatement bbstat = (BasicBlockStatement)first; - int[] values = ((SwitchInstruction)bbstat.getBlock().getLastInstruction()).getValues(); - - List<Statement> nodes = new ArrayList<Statement>(); - List<List<Integer>> edges = new ArrayList<List<Integer>>(); - - // collect regular edges - for(int i=1;i<stats.size();i++) { - - Statement stat = stats.get(i); - - List<Integer> lst = new ArrayList<Integer>(); - for(StatEdge edge: stat.getPredecessorEdges(StatEdge.TYPE_REGULAR)) { - if(edge.getSource() == first) { - lst.add(mapEdgeIndex.get(edge)); - } - } - Collections.sort(lst); - - nodes.add(stat); - edges.add(lst); - } - - // collect exit edges - List<StatEdge> lstExitEdges = first.getSuccessorEdges(StatEdge.TYPE_BREAK | StatEdge.TYPE_CONTINUE); - while(!lstExitEdges.isEmpty()) { - StatEdge edge = lstExitEdges.get(0); - - List<Integer> lst = new ArrayList<Integer>(); - for(int i=lstExitEdges.size()-1;i>=0;i--) { - StatEdge edgeTemp = lstExitEdges.get(i); - if(edgeTemp.getDestination() == edge.getDestination() && edgeTemp.getType() == edge.getType()) { - lst.add(mapEdgeIndex.get(edgeTemp)); - lstExitEdges.remove(i); - } - } - Collections.sort(lst); - - nodes.add(null); - edges.add(lst); - } - - // sort edges (bubblesort) - for(int i=0;i<edges.size()-1;i++) { - for(int j=edges.size()-1;j>i;j--) { - if(edges.get(j-1).get(0) > edges.get(j).get(0)) { - edges.set(j, edges.set(j-1, edges.get(j))); - nodes.set(j, nodes.set(j-1, nodes.get(j))); - } - } - } - - // sort statement cliques - for(int index = 0; index < nodes.size(); index++) { - Statement stat = nodes.get(index); - - if(stat != null) { - HashSet<Statement> setPreds = new HashSet<Statement>(stat.getNeighbours(StatEdge.TYPE_REGULAR, DIRECTION_BACKWARD)); - setPreds.remove(first); - - if(!setPreds.isEmpty()) { - Statement pred = setPreds.iterator().next(); // assumption: at most one predecessor node besides the head. May not hold true for obfuscated code. - for(int j=0;j<nodes.size();j++) { - if(j != (index - 1) && nodes.get(j) == pred) { - nodes.add(j+1, stat); - edges.add(j+1, edges.get(index)); - - if(j > index) { - nodes.remove(index); - edges.remove(index); - index--; - } else { - nodes.remove(index + 1); - edges.remove(index + 1); - } - break; - } - } - } - } - } - - // translate indices back into edges - List<List<StatEdge>> lstEdges = new ArrayList<List<StatEdge>>(); - List<List<ConstExprent>> lstValues = new ArrayList<List<ConstExprent>>(); - - for(List<Integer> lst: edges) { - List<StatEdge> lste = new ArrayList<StatEdge>(); - List<ConstExprent> lstv = new ArrayList<ConstExprent>(); - - List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL); - for(Integer in: lst) { - int index = in==lstSuccs.size()?0:in; - - lste.add(lstSuccs.get(index)); - lstv.add(index==0?null:new ConstExprent(values[index-1], false)); - } - lstEdges.add(lste); - lstValues.add(lstv); - } - - // replace null statements with dummy basic blocks - for(int i=0;i<nodes.size();i++) { - if(nodes.get(i) == null) { - BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock( - DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER))); - - StatEdge sample_edge = lstEdges.get(i).get(0); - - bstat.addSuccessor(new StatEdge(sample_edge.getType(), bstat, sample_edge.getDestination(), sample_edge.closure)); - - for(StatEdge edge : lstEdges.get(i)) { - - edge.getSource().changeEdgeType(DIRECTION_FORWARD, edge, StatEdge.TYPE_REGULAR); - edge.closure.getLabelEdges().remove(edge); - - edge.getDestination().removePredecessor(edge); - edge.getSource().changeEdgeNode(DIRECTION_FORWARD, edge, bstat); - bstat.addPredecessor(edge); - } - - nodes.set(i, bstat); - stats.addWithKey(bstat, bstat.id); - bstat.setParent(this); - } - } - - caseStatements = nodes; - caseEdges = lstEdges; - caseValues = lstValues; - } - - public List<Exprent> getHeadexprentList() { - return headexprent; - } - - public Exprent getHeadexprent() { - return headexprent.get(0); - } - - public List<List<StatEdge>> getCaseEdges() { - return caseEdges; - } - - public List<Statement> getCaseStatements() { - return caseStatements; - } - - public StatEdge getDefault_edge() { - return default_edge; - } - - public List<List<ConstExprent>> getCaseValues() { - return caseValues; - } + // ***************************************************************************** + // private fields + // ***************************************************************************** + + private List<Statement> caseStatements = new ArrayList<Statement>(); + + private List<List<StatEdge>> caseEdges = new ArrayList<List<StatEdge>>(); + + private List<List<ConstExprent>> caseValues = new ArrayList<List<ConstExprent>>(); + + private StatEdge default_edge; + + private List<Exprent> headexprent = new ArrayList<Exprent>(); + + // ***************************************************************************** + // constructors + // ***************************************************************************** + + private SwitchStatement() { + type = TYPE_SWITCH; + + headexprent.add(null); + } + + private SwitchStatement(Statement head, Statement poststat) { + + this(); + + first = head; + stats.addWithKey(head, head.id); + + // find post node + Set<Statement> lstNodes = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_REGULAR, DIRECTION_FORWARD)); + + // cluster nodes + if (poststat != null) { + post = poststat; + lstNodes.remove(post); + } + + default_edge = head.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0); + + for (Statement st : lstNodes) { + stats.addWithKey(st, st.id); + } + } + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public static Statement isHead(Statement head) { + + if (head.type == Statement.TYPE_BASICBLOCK && head.getLastBasicType() == Statement.LASTBASICTYPE_SWITCH) { + + List<Statement> lst = new ArrayList<Statement>(); + if (DecHelper.isChoiceStatement(head, lst)) { + Statement post = lst.remove(0); + + for (Statement st : lst) { + if (st.isMonitorEnter()) { + return null; + } + } + + if (DecHelper.checkStatementExceptions(lst)) { + return new SwitchStatement(head, post); + } + } + } + + return null; + } + + public String toJava(int indent) { + + String indstr = InterpreterUtil.getIndentString(indent); + + String new_line_separator = DecompilerContext.getNewLineSeparator(); + + StringBuilder buf = new StringBuilder(); + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); + buf.append(first.toJava(indent)); + + if (isLabeled()) { + buf.append(indstr + "label" + this.id + ":" + new_line_separator); + } + + buf.append(indstr + headexprent.get(0).toJava(indent) + " {" + new_line_separator); + + VarType switch_type = headexprent.get(0).getExprType(); + + for (int i = 0; i < caseStatements.size(); i++) { + + Statement stat = caseStatements.get(i); + List<StatEdge> edges = caseEdges.get(i); + List<ConstExprent> values = caseValues.get(i); + + for (int j = 0; j < edges.size(); j++) { + if (edges.get(j) == default_edge) { + buf.append(indstr + "default:" + new_line_separator); + } + else { + ConstExprent value = (ConstExprent)values.get(j).copy(); + value.setConsttype(switch_type); + + buf.append(indstr + "case " + value.toJava(indent) + ":" + new_line_separator); + } + } + + buf.append(ExprProcessor.jmpWrapper(stat, indent + 1, false)); + } + + buf.append(indstr + "}" + new_line_separator); + + return buf.toString(); + } + + public void initExprents() { + SwitchExprent swexpr = (SwitchExprent)first.getExprents().remove(first.getExprents().size() - 1); + swexpr.setCaseValues(caseValues); + + headexprent.set(0, swexpr); + } + + public List<Object> getSequentialObjects() { + + List<Object> lst = new ArrayList<Object>(stats); + lst.add(1, headexprent.get(0)); + + return lst; + } + + public void replaceExprent(Exprent oldexpr, Exprent newexpr) { + if (headexprent.get(0) == oldexpr) { + headexprent.set(0, newexpr); + } + } + + public void replaceStatement(Statement oldstat, Statement newstat) { + + for (int i = 0; i < caseStatements.size(); i++) { + if (caseStatements.get(i) == oldstat) { + caseStatements.set(i, newstat); + } + } + + super.replaceStatement(oldstat, newstat); + } + + public Statement getSimpleCopy() { + return new SwitchStatement(); + } + + public void initSimpleCopy() { + first = stats.get(0); + default_edge = first.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0); + + sortEdgesAndNodes(); + } + + // ***************************************************************************** + // private methods + // ***************************************************************************** + + public void sortEdgesAndNodes() { + + HashMap<StatEdge, Integer> mapEdgeIndex = new HashMap<StatEdge, Integer>(); + + List<StatEdge> lstFirstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL); + for (int i = 0; i < lstFirstSuccs.size(); i++) { + mapEdgeIndex.put(lstFirstSuccs.get(i), i == 0 ? lstFirstSuccs.size() : i); + } + + // case values + BasicBlockStatement bbstat = (BasicBlockStatement)first; + int[] values = ((SwitchInstruction)bbstat.getBlock().getLastInstruction()).getValues(); + + List<Statement> nodes = new ArrayList<Statement>(); + List<List<Integer>> edges = new ArrayList<List<Integer>>(); + + // collect regular edges + for (int i = 1; i < stats.size(); i++) { + + Statement stat = stats.get(i); + + List<Integer> lst = new ArrayList<Integer>(); + for (StatEdge edge : stat.getPredecessorEdges(StatEdge.TYPE_REGULAR)) { + if (edge.getSource() == first) { + lst.add(mapEdgeIndex.get(edge)); + } + } + Collections.sort(lst); + + nodes.add(stat); + edges.add(lst); + } + + // collect exit edges + List<StatEdge> lstExitEdges = first.getSuccessorEdges(StatEdge.TYPE_BREAK | StatEdge.TYPE_CONTINUE); + while (!lstExitEdges.isEmpty()) { + StatEdge edge = lstExitEdges.get(0); + + List<Integer> lst = new ArrayList<Integer>(); + for (int i = lstExitEdges.size() - 1; i >= 0; i--) { + StatEdge edgeTemp = lstExitEdges.get(i); + if (edgeTemp.getDestination() == edge.getDestination() && edgeTemp.getType() == edge.getType()) { + lst.add(mapEdgeIndex.get(edgeTemp)); + lstExitEdges.remove(i); + } + } + Collections.sort(lst); + + nodes.add(null); + edges.add(lst); + } + + // sort edges (bubblesort) + for (int i = 0; i < edges.size() - 1; i++) { + for (int j = edges.size() - 1; j > i; j--) { + if (edges.get(j - 1).get(0) > edges.get(j).get(0)) { + edges.set(j, edges.set(j - 1, edges.get(j))); + nodes.set(j, nodes.set(j - 1, nodes.get(j))); + } + } + } + + // sort statement cliques + for (int index = 0; index < nodes.size(); index++) { + Statement stat = nodes.get(index); + + if (stat != null) { + HashSet<Statement> setPreds = new HashSet<Statement>(stat.getNeighbours(StatEdge.TYPE_REGULAR, DIRECTION_BACKWARD)); + setPreds.remove(first); + + if (!setPreds.isEmpty()) { + Statement pred = + setPreds.iterator().next(); // assumption: at most one predecessor node besides the head. May not hold true for obfuscated code. + for (int j = 0; j < nodes.size(); j++) { + if (j != (index - 1) && nodes.get(j) == pred) { + nodes.add(j + 1, stat); + edges.add(j + 1, edges.get(index)); + + if (j > index) { + nodes.remove(index); + edges.remove(index); + index--; + } + else { + nodes.remove(index + 1); + edges.remove(index + 1); + } + break; + } + } + } + } + } + + // translate indices back into edges + List<List<StatEdge>> lstEdges = new ArrayList<List<StatEdge>>(); + List<List<ConstExprent>> lstValues = new ArrayList<List<ConstExprent>>(); + + for (List<Integer> lst : edges) { + List<StatEdge> lste = new ArrayList<StatEdge>(); + List<ConstExprent> lstv = new ArrayList<ConstExprent>(); + + List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL); + for (Integer in : lst) { + int index = in == lstSuccs.size() ? 0 : in; + + lste.add(lstSuccs.get(index)); + lstv.add(index == 0 ? null : new ConstExprent(values[index - 1], false)); + } + lstEdges.add(lste); + lstValues.add(lstv); + } + + // replace null statements with dummy basic blocks + for (int i = 0; i < nodes.size(); i++) { + if (nodes.get(i) == null) { + BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock( + DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER))); + + StatEdge sample_edge = lstEdges.get(i).get(0); + + bstat.addSuccessor(new StatEdge(sample_edge.getType(), bstat, sample_edge.getDestination(), sample_edge.closure)); + + for (StatEdge edge : lstEdges.get(i)) { + + edge.getSource().changeEdgeType(DIRECTION_FORWARD, edge, StatEdge.TYPE_REGULAR); + edge.closure.getLabelEdges().remove(edge); + + edge.getDestination().removePredecessor(edge); + edge.getSource().changeEdgeNode(DIRECTION_FORWARD, edge, bstat); + bstat.addPredecessor(edge); + } + + nodes.set(i, bstat); + stats.addWithKey(bstat, bstat.id); + bstat.setParent(this); + } + } + + caseStatements = nodes; + caseEdges = lstEdges; + caseValues = lstValues; + } + + public List<Exprent> getHeadexprentList() { + return headexprent; + } + + public Exprent getHeadexprent() { + return headexprent.get(0); + } + + public List<List<StatEdge>> getCaseEdges() { + return caseEdges; + } + + public List<Statement> getCaseStatements() { + return caseStatements; + } + + public StatEdge getDefault_edge() { + return default_edge; + } + public List<List<ConstExprent>> getCaseValues() { + return caseValues; + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java index 5336f12..3fcb042 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java @@ -1,22 +1,20 @@ /* - * Fernflower - The Analytical Java Decompiler - * http://www.reversed-java.com + * Copyright 2000-2014 JetBrains s.r.o. * - * (C) 2008 - 2010, Stiver + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This software is NEITHER public domain NOR free software - * as per GNU License. See license.txt for more details. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This software is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.jetbrains.java.decompiler.modules.decompiler.stats; -import java.util.ArrayList; -import java.util.List; - import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.SequenceHelper; @@ -24,131 +22,132 @@ import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; import org.jetbrains.java.decompiler.util.InterpreterUtil; +import java.util.ArrayList; +import java.util.List; + public class SynchronizedStatement extends Statement { - private Statement body; - - private List<Exprent> headexprent = new ArrayList<Exprent>(); - - // ***************************************************************************** - // constructors - // ***************************************************************************** - - public SynchronizedStatement() { - type = TYPE_SYNCRONIZED; - - headexprent.add(null); - } - - public SynchronizedStatement(Statement head, Statement body, Statement exc) { - - this(); - - first = head; - stats.addWithKey(head, head.id); - - this.body = body; - stats.addWithKey(body, body.id); - - stats.addWithKey(exc, exc.id); - - List<StatEdge> lstSuccs = body.getSuccessorEdges(STATEDGE_DIRECT_ALL); - if(!lstSuccs.isEmpty()) { - StatEdge edge = lstSuccs.get(0); - if(edge.getType() == StatEdge.TYPE_REGULAR) { - post = edge.getDestination(); - } - } - - } - - - // ***************************************************************************** - // public methods - // ***************************************************************************** - - public String toJava(int indent) { - String indstr = InterpreterUtil.getIndentString(indent); - - String new_line_separator = DecompilerContext.getNewLineSeparator(); - - StringBuffer buf = new StringBuffer(); - buf.append(ExprProcessor.listToJava(varDefinitions, indent)); - buf.append(first.toJava(indent)); - - if(isLabeled()) { - buf.append(indstr+"label"+this.id+":" + new_line_separator); - } - - buf.append(indstr+headexprent.get(0).toJava(indent)+" {" + new_line_separator); - buf.append(ExprProcessor.jmpWrapper(body, indent+1, true)); - buf.append(indstr+"}" + new_line_separator); - - return buf.toString(); - } - - public void initExprents() { - headexprent.set(0, first.getExprents().remove(first.getExprents().size()-1)); - } - - public List<Object> getSequentialObjects() { - - List<Object> lst = new ArrayList<Object>(stats); - lst.add(1, headexprent.get(0)); - - return lst; - } - - public void replaceExprent(Exprent oldexpr, Exprent newexpr) { - if(headexprent.get(0) == oldexpr) { - headexprent.set(0, newexpr); - } - } - - public void replaceStatement(Statement oldstat, Statement newstat) { - - if(body == oldstat) { - body = newstat; - } - - super.replaceStatement(oldstat, newstat); - } - - public void removeExc() { - Statement exc = stats.get(2); - SequenceHelper.destroyStatementContent(exc, true); - - stats.removeWithKey(exc.id); - } - - public Statement getSimpleCopy() { - return new SynchronizedStatement(); - } - - public void initSimpleCopy() { - first = stats.get(0); - body = stats.get(1); - } - - // ***************************************************************************** - // getter and setter methods - // ***************************************************************************** - - public Statement getBody() { - return body; - } - - public void setBody(Statement body) { - this.body = body; - } - - public List<Exprent> getHeadexprentList() { - return headexprent; - } - - public Exprent getHeadexprent() { - return headexprent.get(0); - } - + private Statement body; + + private List<Exprent> headexprent = new ArrayList<Exprent>(); + + // ***************************************************************************** + // constructors + // ***************************************************************************** + + public SynchronizedStatement() { + type = TYPE_SYNCRONIZED; + + headexprent.add(null); + } + + public SynchronizedStatement(Statement head, Statement body, Statement exc) { + + this(); + + first = head; + stats.addWithKey(head, head.id); + + this.body = body; + stats.addWithKey(body, body.id); + + stats.addWithKey(exc, exc.id); + + List<StatEdge> lstSuccs = body.getSuccessorEdges(STATEDGE_DIRECT_ALL); + if (!lstSuccs.isEmpty()) { + StatEdge edge = lstSuccs.get(0); + if (edge.getType() == StatEdge.TYPE_REGULAR) { + post = edge.getDestination(); + } + } + } + + + // ***************************************************************************** + // public methods + // ***************************************************************************** + + public String toJava(int indent) { + String indstr = InterpreterUtil.getIndentString(indent); + + String new_line_separator = DecompilerContext.getNewLineSeparator(); + + StringBuffer buf = new StringBuffer(); + buf.append(ExprProcessor.listToJava(varDefinitions, indent)); + buf.append(first.toJava(indent)); + + if (isLabeled()) { + buf.append(indstr + "label" + this.id + ":" + new_line_separator); + } + + buf.append(indstr + headexprent.get(0).toJava(indent) + " {" + new_line_separator); + buf.append(ExprProcessor.jmpWrapper(body, indent + 1, true)); + buf.append(indstr + "}" + new_line_separator); + + return buf.toString(); + } + + public void initExprents() { + headexprent.set(0, first.getExprents().remove(first.getExprents().size() - 1)); + } + + public List<Object> getSequentialObjects() { + + List<Object> lst = new ArrayList<Object>(stats); + lst.add(1, headexprent.get(0)); + + return lst; + } + + public void replaceExprent(Exprent oldexpr, Exprent newexpr) { + if (headexprent.get(0) == oldexpr) { + headexprent.set(0, newexpr); + } + } + + public void replaceStatement(Statement oldstat, Statement newstat) { + + if (body == oldstat) { + body = newstat; + } + + super.replaceStatement(oldstat, newstat); + } + + public void removeExc() { + Statement exc = stats.get(2); + SequenceHelper.destroyStatementContent(exc, true); + + stats.removeWithKey(exc.id); + } + + public Statement getSimpleCopy() { + return new SynchronizedStatement(); + } + + public void initSimpleCopy() { + first = stats.get(0); + body = stats.get(1); + } + + // ***************************************************************************** + // getter and setter methods + // ***************************************************************************** + + public Statement getBody() { + return body; + } + + public void setBody(Statement body) { + this.body = body; + } + + public List<Exprent> getHeadexprentList() { + return headexprent; + } + + public Exprent getHeadexprent() { + return headexprent.get(0); + } } |