Pseudocode: Introduce "merge" instruction
This commit is contained in:
@@ -118,6 +118,12 @@ public interface JetControlFlowBuilder {
|
|||||||
boolean synthetic
|
boolean synthetic
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
PseudoValue merge(
|
||||||
|
@NotNull JetExpression expression,
|
||||||
|
@NotNull List<PseudoValue> inputValues
|
||||||
|
);
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
PseudoValue readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor);
|
PseudoValue readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor);
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -76,6 +76,14 @@ public abstract class JetControlFlowBuilderAdapter implements JetControlFlowBuil
|
|||||||
return getDelegateBuilder().magic(instructionElement, valueElement, inputValues, synthetic);
|
return getDelegateBuilder().magic(instructionElement, valueElement, inputValues, synthetic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public PseudoValue merge(
|
||||||
|
@NotNull JetExpression expression, @NotNull List<PseudoValue> inputValues
|
||||||
|
) {
|
||||||
|
return getDelegateBuilder().merge(expression, inputValues);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public PseudoValue readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
|
public PseudoValue readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ public class JetControlFlowProcessor {
|
|||||||
builder.bindValue(values.get(0), to);
|
builder.bindValue(values.get(0), to);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
builder.magic(to, to, values, true);
|
builder.merge(to, values);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ public class JetFlowInformationProvider {
|
|||||||
for (Instruction deadInstruction : pseudocode.getDeadInstructions()) {
|
for (Instruction deadInstruction : pseudocode.getDeadInstructions()) {
|
||||||
if (!(deadInstruction instanceof JetElementInstruction)
|
if (!(deadInstruction instanceof JetElementInstruction)
|
||||||
|| deadInstruction instanceof LoadUnitValueInstruction
|
|| deadInstruction instanceof LoadUnitValueInstruction
|
||||||
|
|| deadInstruction instanceof MergeInstruction
|
||||||
|| (deadInstruction instanceof MagicInstruction && ((MagicInstruction) deadInstruction).getSynthetic())) continue;
|
|| (deadInstruction instanceof MagicInstruction && ((MagicInstruction) deadInstruction).getSynthetic())) continue;
|
||||||
|
|
||||||
JetElement element = ((JetElementInstruction) deadInstruction).getElement();
|
JetElement element = ((JetElementInstruction) deadInstruction).getElement();
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.Instruction;
|
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.Instruction;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitorWithResult;
|
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.InstructionVisitorWithResult;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.MagicInstruction;
|
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.MagicInstruction;
|
||||||
|
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.MergeInstruction;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.AbstractJumpInstruction;
|
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.AbstractJumpInstruction;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.ThrowExceptionInstruction;
|
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.jumps.ThrowExceptionInstruction;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.MarkInstruction;
|
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.MarkInstruction;
|
||||||
@@ -76,4 +77,9 @@ public class TailRecursionDetector extends InstructionVisitorWithResult<Boolean>
|
|||||||
public Boolean visitMagic(@NotNull MagicInstruction instruction) {
|
public Boolean visitMagic(@NotNull MagicInstruction instruction) {
|
||||||
return instruction.getSynthetic();
|
return instruction.getSynthetic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean visitMerge(@NotNull MergeInstruction instruction) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -437,6 +437,14 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
return instruction.getOutputValue();
|
return instruction.getOutputValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public PseudoValue merge(@NotNull JetExpression expression, @NotNull List<PseudoValue> inputValues) {
|
||||||
|
MergeInstruction instruction = MergeInstruction.object$.create(expression, getCurrentScope(), inputValues, valueFactory);
|
||||||
|
add(instruction);
|
||||||
|
return instruction.getOutputValue();
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public PseudoValue readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
|
public PseudoValue readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
|
||||||
|
|||||||
+4
@@ -101,6 +101,10 @@ public open class InstructionVisitor() {
|
|||||||
visitOperation(instruction)
|
visitOperation(instruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public open fun visitMerge(instruction: MergeInstruction) {
|
||||||
|
visitOperation(instruction)
|
||||||
|
}
|
||||||
|
|
||||||
public open fun visitCompilationErrorInstruction(instruction: CompilationErrorInstruction) {
|
public open fun visitCompilationErrorInstruction(instruction: CompilationErrorInstruction) {
|
||||||
visitInstructionWithNext(instruction)
|
visitInstructionWithNext(instruction)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -100,6 +100,10 @@ public abstract class InstructionVisitorWithResult<R>() {
|
|||||||
return visitOperation(instruction)
|
return visitOperation(instruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public open fun visitMerge(instruction: MergeInstruction): R {
|
||||||
|
return visitOperation(instruction)
|
||||||
|
}
|
||||||
|
|
||||||
public open fun visitCompilationErrorInstruction(instruction: CompilationErrorInstruction): R {
|
public open fun visitCompilationErrorInstruction(instruction: CompilationErrorInstruction): R {
|
||||||
return visitInstructionWithNext(instruction)
|
return visitInstructionWithNext(instruction)
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-5
@@ -52,6 +52,11 @@ public abstract class OperationInstruction protected(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait StrictlyValuedOperationInstruction: OperationInstruction {
|
||||||
|
override val outputValue: PseudoValue
|
||||||
|
get() = resultValue!!
|
||||||
|
}
|
||||||
|
|
||||||
public class CallInstruction private(
|
public class CallInstruction private(
|
||||||
element: JetElement,
|
element: JetElement,
|
||||||
lexicalScope: LexicalScope,
|
lexicalScope: LexicalScope,
|
||||||
@@ -95,16 +100,13 @@ public class CallInstruction private(
|
|||||||
// denote value transformation which can't be expressed by other instructions (such as call or read)
|
// denote value transformation which can't be expressed by other instructions (such as call or read)
|
||||||
// pass more than one value to instruction which formally requires only one (e.g. jump)
|
// pass more than one value to instruction which formally requires only one (e.g. jump)
|
||||||
// "Synthetic" means that the instruction does not correspond to some operation explicitly expressed by PSI element
|
// "Synthetic" means that the instruction does not correspond to some operation explicitly expressed by PSI element
|
||||||
// Examples: merging branches of 'if', 'when' and 'try' expressions, providing initial values for parameters, etc.
|
// Examples: providing initial values for parameters, missing right-hand side in assignments
|
||||||
public class MagicInstruction(
|
public class MagicInstruction(
|
||||||
element: JetElement,
|
element: JetElement,
|
||||||
lexicalScope: LexicalScope,
|
lexicalScope: LexicalScope,
|
||||||
val synthetic: Boolean,
|
val synthetic: Boolean,
|
||||||
inputValues: List<PseudoValue>
|
inputValues: List<PseudoValue>
|
||||||
) : OperationInstruction(element, lexicalScope, inputValues) {
|
) : OperationInstruction(element, lexicalScope, inputValues), StrictlyValuedOperationInstruction {
|
||||||
override val outputValue: PseudoValue
|
|
||||||
get() = resultValue!!
|
|
||||||
|
|
||||||
override fun accept(visitor: InstructionVisitor) {
|
override fun accept(visitor: InstructionVisitor) {
|
||||||
visitor.visitMagic(this)
|
visitor.visitMagic(this)
|
||||||
}
|
}
|
||||||
@@ -128,4 +130,33 @@ public class MagicInstruction(
|
|||||||
factory: PseudoValueFactory
|
factory: PseudoValueFactory
|
||||||
): MagicInstruction = MagicInstruction(element, lexicalScope, synthetic, inputValues).setResult(factory, valueElement) as MagicInstruction
|
): MagicInstruction = MagicInstruction(element, lexicalScope, synthetic, inputValues).setResult(factory, valueElement) as MagicInstruction
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merges values produced by alternative control-flow paths (such as 'if' branches)
|
||||||
|
class MergeInstruction private(
|
||||||
|
element: JetElement,
|
||||||
|
lexicalScope: LexicalScope,
|
||||||
|
inputValues: List<PseudoValue>
|
||||||
|
): OperationInstruction(element, lexicalScope, inputValues), StrictlyValuedOperationInstruction {
|
||||||
|
override fun accept(visitor: InstructionVisitor) {
|
||||||
|
visitor.visitMerge(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
|
||||||
|
return visitor.visitMerge(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createCopy() =
|
||||||
|
MergeInstruction(element, lexicalScope, inputValues).setResult(resultValue)
|
||||||
|
|
||||||
|
override fun toString() = renderInstruction("merge", render(element))
|
||||||
|
|
||||||
|
class object {
|
||||||
|
fun create(
|
||||||
|
element: JetElement,
|
||||||
|
lexicalScope: LexicalScope,
|
||||||
|
inputValues: List<PseudoValue>,
|
||||||
|
factory: PseudoValueFactory
|
||||||
|
): MergeInstruction = MergeInstruction(element, lexicalScope, inputValues).setResult(factory) as MergeInstruction
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +110,7 @@ L6 [skipFinallyToErrorBlock]:
|
|||||||
3 mark({ return 1 }) PREV:[jmp(L6 [skipFinallyToErrorBlock])]
|
3 mark({ return 1 }) PREV:[jmp(L6 [skipFinallyToErrorBlock])]
|
||||||
r(1) -> <v5>
|
r(1) -> <v5>
|
||||||
ret(*|<v5>) L1 NEXT:[<END>]
|
ret(*|<v5>) L1 NEXT:[<END>]
|
||||||
- 2 magic(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { return 1 }|<v0>, <v2>, <v4>) -> <v6> PREV:[]
|
- 2 merge(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { return 1 }|<v0>, <v2>, <v4>) -> <v6> PREV:[]
|
||||||
L1:
|
L1:
|
||||||
1 <END> NEXT:[<SINK>] PREV:[ret(*|<v5>) L1, ret(*|<v5>) L1]
|
1 <END> NEXT:[<SINK>] PREV:[ret(*|<v5>) L1, ret(*|<v5>) L1]
|
||||||
error:
|
error:
|
||||||
@@ -195,9 +195,9 @@ L10 [skipFinallyToErrorBlock]:
|
|||||||
call(cond, cond) -> <v6>
|
call(cond, cond) -> <v6>
|
||||||
jf(copy L12|<v6>) NEXT:[jmp(L2 [loop entry point]), ret L1]
|
jf(copy L12|<v6>) NEXT:[jmp(L2 [loop entry point]), ret L1]
|
||||||
ret L1 NEXT:[<END>]
|
ret L1 NEXT:[<END>]
|
||||||
- jmp(copy L13) NEXT:[magic(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue }|<v1>, <v3>, <v5>) -> <v7>] PREV:[]
|
- jmp(copy L13) NEXT:[merge(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue }|<v1>, <v3>, <v5>) -> <v7>] PREV:[]
|
||||||
jmp(L2 [loop entry point]) NEXT:[mark(cond())] PREV:[jf(copy L12|<v6>)]
|
jmp(L2 [loop entry point]) NEXT:[mark(cond())] PREV:[jf(copy L12|<v6>)]
|
||||||
- 3 magic(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue }|<v1>, <v3>, <v5>) -> <v7> PREV:[]
|
- 3 merge(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { if (cond()) return else continue }|<v1>, <v3>, <v5>) -> <v7> PREV:[]
|
||||||
- 2 jmp(L2 [loop entry point]) NEXT:[mark(cond())] PREV:[]
|
- 2 jmp(L2 [loop entry point]) NEXT:[mark(cond())] PREV:[]
|
||||||
L3 [loop exit point]:
|
L3 [loop exit point]:
|
||||||
read (Unit) PREV:[jf(L3 [loop exit point]|<v0>)]
|
read (Unit) PREV:[jf(L3 [loop exit point]|<v0>)]
|
||||||
@@ -276,7 +276,7 @@ L6 [skipFinallyToErrorBlock]:
|
|||||||
jf(copy L9 [loop exit point]|<v5>) NEXT:[read (Unit), jmp(copy L8 [loop entry point])]
|
jf(copy L9 [loop exit point]|<v5>) NEXT:[read (Unit), jmp(copy L8 [loop entry point])]
|
||||||
jmp(copy L8 [loop entry point]) NEXT:[mark(cond())]
|
jmp(copy L8 [loop entry point]) NEXT:[mark(cond())]
|
||||||
read (Unit) PREV:[jf(copy L9 [loop exit point]|<v5>)]
|
read (Unit) PREV:[jf(copy L9 [loop exit point]|<v5>)]
|
||||||
2 magic(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { while (cond()); }|<v0>, <v2>, <v4>) -> <v6>
|
2 merge(try { doSmth() } catch (e: NullPointerException) { doSmth1() } catch (e: Exception) { doSmth2() } finally { while (cond()); }|<v0>, <v2>, <v4>) -> <v6>
|
||||||
L1:
|
L1:
|
||||||
1 <END> NEXT:[<SINK>]
|
1 <END> NEXT:[<SINK>]
|
||||||
error:
|
error:
|
||||||
|
|||||||
@@ -46,11 +46,11 @@ L0:
|
|||||||
r(true) -> <v5>
|
r(true) -> <v5>
|
||||||
jf(L2|<v5>) NEXT:[r(2) -> <v7>, r(1) -> <v6>]
|
jf(L2|<v5>) NEXT:[r(2) -> <v7>, r(1) -> <v6>]
|
||||||
r(1) -> <v6>
|
r(1) -> <v6>
|
||||||
jmp(L3) NEXT:[magic(if (true) 1 else 2|<v6>, <v7>) -> <v8>]
|
jmp(L3) NEXT:[merge(if (true) 1 else 2|<v6>, <v7>) -> <v8>]
|
||||||
L2:
|
L2:
|
||||||
r(2) -> <v7> PREV:[jf(L2|<v5>)]
|
r(2) -> <v7> PREV:[jf(L2|<v5>)]
|
||||||
L3:
|
L3:
|
||||||
magic(if (true) 1 else 2|<v6>, <v7>) -> <v8> PREV:[jmp(L3), r(2) -> <v7>]
|
merge(if (true) 1 else 2|<v6>, <v7>) -> <v8> PREV:[jmp(L3), r(2) -> <v7>]
|
||||||
w(x|<v8>)
|
w(x|<v8>)
|
||||||
v(val y = true && false)
|
v(val y = true && false)
|
||||||
r(true) -> <v9>
|
r(true) -> <v9>
|
||||||
|
|||||||
@@ -31,12 +31,12 @@ L0:
|
|||||||
jf(L2|<v2>) NEXT:[mark({ 2 }), mark({ 1 })]
|
jf(L2|<v2>) NEXT:[mark({ 2 }), mark({ 1 })]
|
||||||
3 mark({ 1 })
|
3 mark({ 1 })
|
||||||
r(1) -> <v3>
|
r(1) -> <v3>
|
||||||
2 jmp(L3) NEXT:[magic(if (a) { 1 } else { 2 }|<v3>, <v4>) -> <v5>]
|
2 jmp(L3) NEXT:[merge(if (a) { 1 } else { 2 }|<v3>, <v4>) -> <v5>]
|
||||||
L2:
|
L2:
|
||||||
3 mark({ 2 }) PREV:[jf(L2|<v2>)]
|
3 mark({ 2 }) PREV:[jf(L2|<v2>)]
|
||||||
r(2) -> <v4>
|
r(2) -> <v4>
|
||||||
L3:
|
L3:
|
||||||
2 magic(if (a) { 1 } else { 2 }|<v3>, <v4>) -> <v5> PREV:[jmp(L3), r(2) -> <v4>]
|
2 merge(if (a) { 1 } else { 2 }|<v3>, <v4>) -> <v5> PREV:[jmp(L3), r(2) -> <v4>]
|
||||||
r(3) -> <v6>
|
r(3) -> <v6>
|
||||||
mark(if (a && b) 5 else 6)
|
mark(if (a && b) 5 else 6)
|
||||||
r(a) -> <v7>
|
r(a) -> <v7>
|
||||||
@@ -45,11 +45,11 @@ L3:
|
|||||||
L4:
|
L4:
|
||||||
jf(L5) NEXT:[r(6) -> <v10>, r(5) -> <v9>] PREV:[jf(L4|<v7>), r(b) -> <v8>]
|
jf(L5) NEXT:[r(6) -> <v10>, r(5) -> <v9>] PREV:[jf(L4|<v7>), r(b) -> <v8>]
|
||||||
r(5) -> <v9>
|
r(5) -> <v9>
|
||||||
jmp(L6) NEXT:[magic(if (a && b) 5 else 6|<v9>, <v10>) -> <v11>]
|
jmp(L6) NEXT:[merge(if (a && b) 5 else 6|<v9>, <v10>) -> <v11>]
|
||||||
L5:
|
L5:
|
||||||
r(6) -> <v10> PREV:[jf(L5)]
|
r(6) -> <v10> PREV:[jf(L5)]
|
||||||
L6:
|
L6:
|
||||||
magic(if (a && b) 5 else 6|<v9>, <v10>) -> <v11> PREV:[jmp(L6), r(6) -> <v10>]
|
merge(if (a && b) 5 else 6|<v9>, <v10>) -> <v11> PREV:[jmp(L6), r(6) -> <v10>]
|
||||||
r(7) -> <v12>
|
r(7) -> <v12>
|
||||||
mark(if (a || b) 8 else 9)
|
mark(if (a || b) 8 else 9)
|
||||||
r(a) -> <v13>
|
r(a) -> <v13>
|
||||||
@@ -58,11 +58,11 @@ L6:
|
|||||||
L7:
|
L7:
|
||||||
jf(L8) NEXT:[r(9) -> <v16>, r(8) -> <v15>] PREV:[jt(L7|<v13>), r(b) -> <v14>]
|
jf(L8) NEXT:[r(9) -> <v16>, r(8) -> <v15>] PREV:[jt(L7|<v13>), r(b) -> <v14>]
|
||||||
r(8) -> <v15>
|
r(8) -> <v15>
|
||||||
jmp(L9) NEXT:[magic(if (a || b) 8 else 9|<v15>, <v16>) -> <v17>]
|
jmp(L9) NEXT:[merge(if (a || b) 8 else 9|<v15>, <v16>) -> <v17>]
|
||||||
L8:
|
L8:
|
||||||
r(9) -> <v16> PREV:[jf(L8)]
|
r(9) -> <v16> PREV:[jf(L8)]
|
||||||
L9:
|
L9:
|
||||||
magic(if (a || b) 8 else 9|<v15>, <v16>) -> <v17> PREV:[jmp(L9), r(9) -> <v16>]
|
merge(if (a || b) 8 else 9|<v15>, <v16>) -> <v17> PREV:[jmp(L9), r(9) -> <v16>]
|
||||||
r(10) -> <v18>
|
r(10) -> <v18>
|
||||||
mark(if (a) 11)
|
mark(if (a) 11)
|
||||||
r(a) -> <v19>
|
r(a) -> <v19>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ L5 [skipFinallyToErrorBlock]:
|
|||||||
3 mark({ test() }) PREV:[jmp(L5 [skipFinallyToErrorBlock])]
|
3 mark({ test() }) PREV:[jmp(L5 [skipFinallyToErrorBlock])]
|
||||||
mark(test())
|
mark(test())
|
||||||
call(test, test) -> <v3>
|
call(test, test) -> <v3>
|
||||||
2 magic(try { test() } catch (any : Exception) { test() } finally { test() }|<v0>, <v2>) -> <v4>
|
2 merge(try { test() } catch (any : Exception) { test() } finally { test() }|<v0>, <v2>) -> <v4>
|
||||||
L1:
|
L1:
|
||||||
1 <END> NEXT:[<SINK>]
|
1 <END> NEXT:[<SINK>]
|
||||||
error:
|
error:
|
||||||
|
|||||||
Reference in New Issue
Block a user