mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Continue developing decompiler
This commit is contained in:
parent
5f2019a9b6
commit
96ba2bbf7d
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.teavm.wasm.decompile;
|
||||
|
||||
import org.teavm.wasm.model.expression.WasmBlock;
|
||||
|
||||
public class BlockBreakLabel implements Label {
|
||||
private WasmBlock target;
|
||||
|
||||
public BlockBreakLabel(WasmBlock target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmBlock getTarget() {
|
||||
return target;
|
||||
}
|
||||
}
|
43
core/src/main/java/org/teavm/wasm/decompile/Context.java
Normal file
43
core/src/main/java/org/teavm/wasm/decompile/Context.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.teavm.wasm.decompile;
|
||||
|
||||
import org.teavm.common.DominatorTree;
|
||||
import org.teavm.common.Graph;
|
||||
import org.teavm.common.LoopGraph;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.util.VariableType;
|
||||
import org.teavm.wasm.model.WasmLocal;
|
||||
|
||||
public interface Context {
|
||||
void push(Step step);
|
||||
|
||||
void setLabel(int node, Label label);
|
||||
|
||||
Label getLabel(int node);
|
||||
|
||||
Graph getDomGraph();
|
||||
|
||||
LoopGraph getCfg();
|
||||
|
||||
Program getProgram();
|
||||
|
||||
DominatorTree getDomTree();
|
||||
|
||||
WasmLocal getLocal(int index);
|
||||
|
||||
VariableType getLocalType(int index);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.teavm.wasm.decompile;
|
||||
|
||||
import com.carrotsearch.hppc.IntObjectMap;
|
||||
import com.carrotsearch.hppc.IntObjectOpenHashMap;
|
||||
|
||||
public final class ContextUtils {
|
||||
private ContextUtils() {
|
||||
}
|
||||
|
||||
public static void withLabels(Context context, IntObjectMap<Label> labels) {
|
||||
IntObjectMap<Label> undo = new IntObjectOpenHashMap<>();
|
||||
for (int node : labels.keys().toArray()) {
|
||||
undo.put(node, context.getLabel(node));
|
||||
}
|
||||
context.push(() -> withLabelsImpl(context, undo));
|
||||
withLabelsImpl(context, labels);
|
||||
}
|
||||
|
||||
private static void withLabelsImpl(Context context, IntObjectMap<Label> labels) {
|
||||
for (int node : labels.keys().toArray()) {
|
||||
context.setLabel(node, labels.get(node));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.teavm.wasm.decompile;
|
||||
|
||||
import java.util.List;
|
||||
import org.teavm.model.InvokeDynamicInstruction;
|
||||
import org.teavm.model.instructions.ArrayLengthInstruction;
|
||||
import org.teavm.model.instructions.AssignInstruction;
|
||||
|
@ -53,11 +54,19 @@ import org.teavm.model.instructions.RaiseInstruction;
|
|||
import org.teavm.model.instructions.StringConstantInstruction;
|
||||
import org.teavm.model.instructions.SwitchInstruction;
|
||||
import org.teavm.model.instructions.UnwrapArrayInstruction;
|
||||
import org.teavm.wasm.model.expression.WasmExpression;
|
||||
|
||||
public class DecompilationVisitor implements InstructionVisitor {
|
||||
private List<WasmExpression> expressions;
|
||||
private Context context;
|
||||
|
||||
public DecompilationVisitor(List<WasmExpression> expressions, Context context) {
|
||||
this.expressions = expressions;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(EmptyInstruction insn) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
276
core/src/main/java/org/teavm/wasm/decompile/EnterStep.java
Normal file
276
core/src/main/java/org/teavm/wasm/decompile/EnterStep.java
Normal file
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.teavm.wasm.decompile;
|
||||
|
||||
import com.carrotsearch.hppc.IntObjectMap;
|
||||
import com.carrotsearch.hppc.IntObjectOpenHashMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.teavm.common.DominatorTree;
|
||||
import org.teavm.common.Graph;
|
||||
import org.teavm.common.IntegerArray;
|
||||
import org.teavm.common.Loop;
|
||||
import org.teavm.common.LoopGraph;
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.instructions.BinaryBranchingInstruction;
|
||||
import org.teavm.model.instructions.BranchingCondition;
|
||||
import org.teavm.model.instructions.BranchingInstruction;
|
||||
import org.teavm.model.util.VariableType;
|
||||
import org.teavm.wasm.model.WasmLocal;
|
||||
import org.teavm.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.wasm.model.expression.WasmConditional;
|
||||
import org.teavm.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.wasm.model.expression.WasmFloat32Constant;
|
||||
import org.teavm.wasm.model.expression.WasmFloat64Constant;
|
||||
import org.teavm.wasm.model.expression.WasmFloatBinary;
|
||||
import org.teavm.wasm.model.expression.WasmFloatBinaryOperation;
|
||||
import org.teavm.wasm.model.expression.WasmFloatType;
|
||||
import org.teavm.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.wasm.model.expression.WasmInt64Constant;
|
||||
import org.teavm.wasm.model.expression.WasmIntBinary;
|
||||
import org.teavm.wasm.model.expression.WasmIntBinaryOperation;
|
||||
import org.teavm.wasm.model.expression.WasmIntType;
|
||||
import org.teavm.wasm.model.expression.WasmLocalReference;
|
||||
|
||||
public class EnterStep implements Step {
|
||||
private Context context;
|
||||
private List<WasmExpression> expressions;
|
||||
private List<WasmExpression> innerExpressions;
|
||||
private int node;
|
||||
private DecompilationVisitor decompilationVisitor;
|
||||
|
||||
public EnterStep(Context context, List<WasmExpression> expressions, int node) {
|
||||
this.context = context;
|
||||
this.expressions = expressions;
|
||||
this.innerExpressions = expressions;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform() {
|
||||
LoopGraph cfg = context.getCfg();
|
||||
Graph domGraph = context.getDomGraph();
|
||||
|
||||
Loop loop = cfg.loopAt(node);
|
||||
if (loop != null && loop.getHead() == node) {
|
||||
enterLoop(loop);
|
||||
}
|
||||
|
||||
decompilationVisitor = new DecompilationVisitor(innerExpressions, context);
|
||||
compileInstructions();
|
||||
|
||||
int successors = domGraph.outgoingEdgesCount(node);
|
||||
if (successors == 1) {
|
||||
enterNext(domGraph.outgoingEdges(node)[0]);
|
||||
} else if (successors == 0) {
|
||||
BasicBlock block = context.getProgram().basicBlockAt(node);
|
||||
block.getLastInstruction().acceptVisitor(decompilationVisitor);
|
||||
} else {
|
||||
compileFork();
|
||||
}
|
||||
}
|
||||
|
||||
private void compileInstructions() {
|
||||
BasicBlock block = context.getProgram().basicBlockAt(node);
|
||||
int lastInstructionIndex = block.getInstructions().size() - 1;
|
||||
for (int i = 0; i < lastInstructionIndex; ++i) {
|
||||
block.getInstructions().get(i).acceptVisitor(decompilationVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
private void enterLoop(Loop loop) {
|
||||
WasmBlock wasmLoop = new WasmBlock(true);
|
||||
innerExpressions = wasmLoop.getBody();
|
||||
expressions.add(wasmLoop);
|
||||
LoopExitStep exitStep = new LoopExitStep(expressions, wasmLoop);
|
||||
context.push(exitStep);
|
||||
|
||||
IntObjectMap<Label> newLabels = new IntObjectOpenHashMap<>();
|
||||
int[] exits = findLoopExits(loop);
|
||||
Label breakLabel = exitStep.createBreakLabel();
|
||||
for (int exit : exits) {
|
||||
newLabels.put(exit, breakLabel);
|
||||
}
|
||||
newLabels.put(loop.getHead(), exitStep.createContinueLabel());
|
||||
ContextUtils.withLabels(context, newLabels);
|
||||
}
|
||||
|
||||
private int[] findLoopExits(Loop loop) {
|
||||
IntegerArray exits = new IntegerArray(2);
|
||||
LoopGraph cfg = context.getCfg();
|
||||
for (int i = 0; i < cfg.size(); ++i) {
|
||||
Loop nodeLoop = cfg.loopAt(i);
|
||||
if (nodeLoop != null && nodeLoop.isChildOf(loop)) {
|
||||
for (int successor : cfg.outgoingEdges(i)) {
|
||||
Loop successorLoop = cfg.loopAt(successor);
|
||||
if (successorLoop == null || !successorLoop.isChildOf(loop)) {
|
||||
exits.add(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return exits.getAll();
|
||||
}
|
||||
|
||||
private void compileFork() {
|
||||
Instruction instruction = context.getProgram().basicBlockAt(node).getLastInstruction();
|
||||
if (instruction instanceof BranchingInstruction) {
|
||||
compileFork((BranchingInstruction) instruction);
|
||||
} else if (instruction instanceof BinaryBranchingInstruction) {
|
||||
compileFork((BinaryBranchingInstruction) instruction);
|
||||
}
|
||||
}
|
||||
|
||||
private void compileFork(BranchingInstruction instruction) {
|
||||
WasmLocal local = context.getLocal(instruction.getOperand().getIndex());
|
||||
WasmExpression operand = new WasmLocalReference(local);
|
||||
VariableType operandType = context.getLocalType(instruction.getOperand().getIndex());
|
||||
|
||||
WasmExpression condition;
|
||||
switch (operandType) {
|
||||
case FLOAT:
|
||||
condition = new WasmFloatBinary(WasmFloatType.FLOAT32, getFloatCondition(instruction.getCondition()),
|
||||
operand, new WasmFloat32Constant(0));
|
||||
break;
|
||||
case DOUBLE:
|
||||
condition = new WasmFloatBinary(WasmFloatType.FLOAT64, getFloatCondition(instruction.getCondition()),
|
||||
operand, new WasmFloat64Constant(0));
|
||||
break;
|
||||
case INT:
|
||||
condition = new WasmIntBinary(WasmIntType.INT32, getIntCondition(instruction.getCondition()),
|
||||
operand, new WasmInt32Constant(0));
|
||||
break;
|
||||
case LONG:
|
||||
condition = new WasmIntBinary(WasmIntType.INT64, getIntCondition(instruction.getCondition()),
|
||||
operand, new WasmInt64Constant(0));
|
||||
break;
|
||||
default:
|
||||
condition = new WasmIntBinary(WasmIntType.INT32, getReferenceCondition(instruction.getCondition()),
|
||||
operand, new WasmInt32Constant(0));
|
||||
break;
|
||||
}
|
||||
|
||||
compileIf(condition, instruction.getConsequent().getIndex(), instruction.getAlternative().getIndex());
|
||||
}
|
||||
|
||||
private void compileFork(BinaryBranchingInstruction instruction) {
|
||||
WasmExpression a = new WasmLocalReference(context.getLocal(instruction.getFirstOperand().getIndex()));
|
||||
WasmExpression b = new WasmLocalReference(context.getLocal(instruction.getSecondOperand().getIndex()));
|
||||
|
||||
WasmExpression condition;
|
||||
switch (instruction.getCondition()) {
|
||||
case REFERENCE_EQUAL:
|
||||
case EQUAL:
|
||||
condition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.EQ, a, b);
|
||||
break;
|
||||
case REFERENCE_NOT_EQUAL:
|
||||
case NOT_EQUAL:
|
||||
condition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.NE, a, b);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(instruction.getCondition().toString());
|
||||
}
|
||||
|
||||
compileIf(condition, instruction.getConsequent().getIndex(), instruction.getAlternative().getIndex());
|
||||
}
|
||||
|
||||
private WasmFloatBinaryOperation getFloatCondition(BranchingCondition condition) {
|
||||
switch (condition) {
|
||||
case EQUAL:
|
||||
return WasmFloatBinaryOperation.EQ;
|
||||
case NOT_EQUAL:
|
||||
return WasmFloatBinaryOperation.NE;
|
||||
case GREATER:
|
||||
return WasmFloatBinaryOperation.GT;
|
||||
case GREATER_OR_EQUAL:
|
||||
return WasmFloatBinaryOperation.GE;
|
||||
case LESS:
|
||||
return WasmFloatBinaryOperation.LT;
|
||||
case LESS_OR_EQUAL:
|
||||
return WasmFloatBinaryOperation.LE;
|
||||
case NULL:
|
||||
case NOT_NULL:
|
||||
break;
|
||||
}
|
||||
throw new IllegalArgumentException(condition.toString());
|
||||
}
|
||||
|
||||
private WasmIntBinaryOperation getIntCondition(BranchingCondition condition) {
|
||||
switch (condition) {
|
||||
case EQUAL:
|
||||
return WasmIntBinaryOperation.EQ;
|
||||
case NOT_EQUAL:
|
||||
return WasmIntBinaryOperation.NE;
|
||||
case GREATER:
|
||||
return WasmIntBinaryOperation.GT_SIGNED;
|
||||
case GREATER_OR_EQUAL:
|
||||
return WasmIntBinaryOperation.GE_SIGNED;
|
||||
case LESS:
|
||||
return WasmIntBinaryOperation.LT_SIGNED;
|
||||
case LESS_OR_EQUAL:
|
||||
return WasmIntBinaryOperation.LE_SIGNED;
|
||||
case NULL:
|
||||
case NOT_NULL:
|
||||
break;
|
||||
}
|
||||
throw new IllegalArgumentException(condition.toString());
|
||||
}
|
||||
|
||||
private WasmIntBinaryOperation getReferenceCondition(BranchingCondition condition) {
|
||||
switch (condition) {
|
||||
case NULL:
|
||||
return WasmIntBinaryOperation.EQ;
|
||||
case NOT_NULL:
|
||||
return WasmIntBinaryOperation.NE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw new IllegalArgumentException(condition.toString());
|
||||
}
|
||||
|
||||
private void compileIf(WasmExpression condition, int thenNode, int elseNode) {
|
||||
DominatorTree dom = context.getDomTree();
|
||||
Graph domGraph = context.getDomGraph();
|
||||
|
||||
boolean ownsThen = dom.directlyDominates(node, thenNode);
|
||||
boolean ownsElse = dom.directlyDominates(node, elseNode);
|
||||
int[] exits = Arrays.stream(domGraph.outgoingEdges(node))
|
||||
.filter(n -> n != thenNode && n != elseNode)
|
||||
.toArray();
|
||||
|
||||
if (ownsThen && ownsElse) {
|
||||
WasmConditional conditional = new WasmConditional(condition);
|
||||
innerExpressions.add(conditional);
|
||||
compileBranch(conditional.getElseBlock(), elseNode, exits);
|
||||
compileBranch(conditional.getThenBlock(), thenNode, exits);
|
||||
}
|
||||
}
|
||||
|
||||
private void compileBranch(WasmBlock block, int branchNode, int[] exits) {
|
||||
IntObjectMap<Label> thenLabels = new IntObjectOpenHashMap<>();
|
||||
for (int exit : exits) {
|
||||
thenLabels.put(exit, new BlockBreakLabel(block));
|
||||
}
|
||||
ContextUtils.withLabels(context, thenLabels);
|
||||
context.push(new EnterStep(context, block.getBody(), branchNode));
|
||||
}
|
||||
|
||||
private void enterNext(int nextNode) {
|
||||
context.push(new EnterStep(context, innerExpressions, nextNode));
|
||||
}
|
||||
}
|
22
core/src/main/java/org/teavm/wasm/decompile/Label.java
Normal file
22
core/src/main/java/org/teavm/wasm/decompile/Label.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.teavm.wasm.decompile;
|
||||
|
||||
import org.teavm.wasm.model.expression.WasmBlock;
|
||||
|
||||
public interface Label {
|
||||
WasmBlock getTarget();
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.teavm.wasm.decompile;
|
||||
|
||||
import java.util.List;
|
||||
import org.teavm.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.wasm.model.expression.WasmExpression;
|
||||
|
||||
public class LoopExitStep implements Step {
|
||||
private List<WasmExpression> expressions;
|
||||
private WasmBlock loop;
|
||||
private WasmBlock targetBlock;
|
||||
|
||||
public LoopExitStep(List<WasmExpression> expressions, WasmBlock loop) {
|
||||
this.expressions = expressions;
|
||||
this.loop = loop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform() {
|
||||
if (targetBlock != null) {
|
||||
expressions.add(targetBlock);
|
||||
} else {
|
||||
expressions.add(loop);
|
||||
}
|
||||
targetBlock = null;
|
||||
}
|
||||
|
||||
public Label createBreakLabel() {
|
||||
return () -> {
|
||||
if (targetBlock == null) {
|
||||
targetBlock = new WasmBlock(false);
|
||||
targetBlock.getBody().add(loop);
|
||||
}
|
||||
return targetBlock;
|
||||
};
|
||||
}
|
||||
|
||||
public Label createContinueLabel() {
|
||||
return () -> loop;
|
||||
}
|
||||
}
|
20
core/src/main/java/org/teavm/wasm/decompile/Step.java
Normal file
20
core/src/main/java/org/teavm/wasm/decompile/Step.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.teavm.wasm.decompile;
|
||||
|
||||
public interface Step {
|
||||
void perform();
|
||||
}
|
|
@ -20,5 +20,10 @@ public enum WasmFloatBinaryOperation {
|
|||
SUB,
|
||||
MUL,
|
||||
DIV,
|
||||
|
||||
EQ,
|
||||
NE,
|
||||
LT,
|
||||
LE,
|
||||
GT,
|
||||
GE
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user