Pseudocode: Introduce "merge" instruction
This commit is contained in:
@@ -118,6 +118,12 @@ public interface JetControlFlowBuilder {
|
||||
boolean synthetic
|
||||
);
|
||||
|
||||
@NotNull
|
||||
PseudoValue merge(
|
||||
@NotNull JetExpression expression,
|
||||
@NotNull List<PseudoValue> inputValues
|
||||
);
|
||||
|
||||
@NotNull
|
||||
PseudoValue readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor);
|
||||
@NotNull
|
||||
|
||||
@@ -76,6 +76,14 @@ public abstract class JetControlFlowBuilderAdapter implements JetControlFlowBuil
|
||||
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
|
||||
@Override
|
||||
public PseudoValue readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
|
||||
|
||||
@@ -203,7 +203,7 @@ public class JetControlFlowProcessor {
|
||||
builder.bindValue(values.get(0), to);
|
||||
break;
|
||||
default:
|
||||
builder.magic(to, to, values, true);
|
||||
builder.merge(to, values);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,6 +256,7 @@ public class JetFlowInformationProvider {
|
||||
for (Instruction deadInstruction : pseudocode.getDeadInstructions()) {
|
||||
if (!(deadInstruction instanceof JetElementInstruction)
|
||||
|| deadInstruction instanceof LoadUnitValueInstruction
|
||||
|| deadInstruction instanceof MergeInstruction
|
||||
|| (deadInstruction instanceof MagicInstruction && ((MagicInstruction) deadInstruction).getSynthetic())) continue;
|
||||
|
||||
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.InstructionVisitorWithResult;
|
||||
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.ThrowExceptionInstruction;
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
|
||||
@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
|
||||
@Override
|
||||
public PseudoValue readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
|
||||
|
||||
+4
@@ -101,6 +101,10 @@ public open class InstructionVisitor() {
|
||||
visitOperation(instruction)
|
||||
}
|
||||
|
||||
public open fun visitMerge(instruction: MergeInstruction) {
|
||||
visitOperation(instruction)
|
||||
}
|
||||
|
||||
public open fun visitCompilationErrorInstruction(instruction: CompilationErrorInstruction) {
|
||||
visitInstructionWithNext(instruction)
|
||||
}
|
||||
|
||||
+4
@@ -100,6 +100,10 @@ public abstract class InstructionVisitorWithResult<R>() {
|
||||
return visitOperation(instruction)
|
||||
}
|
||||
|
||||
public open fun visitMerge(instruction: MergeInstruction): R {
|
||||
return visitOperation(instruction)
|
||||
}
|
||||
|
||||
public open fun visitCompilationErrorInstruction(instruction: CompilationErrorInstruction): R {
|
||||
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(
|
||||
element: JetElement,
|
||||
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)
|
||||
// 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
|
||||
// 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(
|
||||
element: JetElement,
|
||||
lexicalScope: LexicalScope,
|
||||
val synthetic: Boolean,
|
||||
inputValues: List<PseudoValue>
|
||||
) : OperationInstruction(element, lexicalScope, inputValues) {
|
||||
override val outputValue: PseudoValue
|
||||
get() = resultValue!!
|
||||
|
||||
) : OperationInstruction(element, lexicalScope, inputValues), StrictlyValuedOperationInstruction {
|
||||
override fun accept(visitor: InstructionVisitor) {
|
||||
visitor.visitMagic(this)
|
||||
}
|
||||
@@ -128,4 +130,33 @@ public class MagicInstruction(
|
||||
factory: PseudoValueFactory
|
||||
): 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])]
|
||||
r(1) -> <v5>
|
||||
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:
|
||||
1 <END> NEXT:[<SINK>] PREV:[ret(*|<v5>) L1, ret(*|<v5>) L1]
|
||||
error:
|
||||
@@ -195,9 +195,9 @@ L10 [skipFinallyToErrorBlock]:
|
||||
call(cond, cond) -> <v6>
|
||||
jf(copy L12|<v6>) NEXT:[jmp(L2 [loop entry point]), ret L1]
|
||||
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>)]
|
||||
- 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:[]
|
||||
L3 [loop exit point]:
|
||||
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])]
|
||||
jmp(copy L8 [loop entry point]) NEXT:[mark(cond())]
|
||||
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:
|
||||
1 <END> NEXT:[<SINK>]
|
||||
error:
|
||||
|
||||
@@ -46,11 +46,11 @@ L0:
|
||||
r(true) -> <v5>
|
||||
jf(L2|<v5>) NEXT:[r(2) -> <v7>, 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:
|
||||
r(2) -> <v7> PREV:[jf(L2|<v5>)]
|
||||
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>)
|
||||
v(val y = true && false)
|
||||
r(true) -> <v9>
|
||||
|
||||
@@ -31,12 +31,12 @@ L0:
|
||||
jf(L2|<v2>) NEXT:[mark({ 2 }), mark({ 1 })]
|
||||
3 mark({ 1 })
|
||||
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:
|
||||
3 mark({ 2 }) PREV:[jf(L2|<v2>)]
|
||||
r(2) -> <v4>
|
||||
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>
|
||||
mark(if (a && b) 5 else 6)
|
||||
r(a) -> <v7>
|
||||
@@ -45,11 +45,11 @@ L3:
|
||||
L4:
|
||||
jf(L5) NEXT:[r(6) -> <v10>, r(5) -> <v9>] PREV:[jf(L4|<v7>), r(b) -> <v8>]
|
||||
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:
|
||||
r(6) -> <v10> PREV:[jf(L5)]
|
||||
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>
|
||||
mark(if (a || b) 8 else 9)
|
||||
r(a) -> <v13>
|
||||
@@ -58,11 +58,11 @@ L6:
|
||||
L7:
|
||||
jf(L8) NEXT:[r(9) -> <v16>, r(8) -> <v15>] PREV:[jt(L7|<v13>), r(b) -> <v14>]
|
||||
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:
|
||||
r(9) -> <v16> PREV:[jf(L8)]
|
||||
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>
|
||||
mark(if (a) 11)
|
||||
r(a) -> <v19>
|
||||
|
||||
@@ -40,7 +40,7 @@ L5 [skipFinallyToErrorBlock]:
|
||||
3 mark({ test() }) PREV:[jmp(L5 [skipFinallyToErrorBlock])]
|
||||
mark(test())
|
||||
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:
|
||||
1 <END> NEXT:[<SINK>]
|
||||
error:
|
||||
|
||||
Reference in New Issue
Block a user