From 67d91f656a048d0784da9b1cfd7383c8f405f5f5 Mon Sep 17 00:00:00 2001 From: mirkosertic Date: Thu, 11 May 2023 17:31:17 +0200 Subject: [PATCH] Prototype for ClassInit optimizations --- .../JSStructuredControlflowCodeGenerator.java | 25 ++++---- ...nCLStructuredControlflowCodeGenerator.java | 5 ++ .../core/backend/sequencer/Sequencer.java | 6 +- .../StructuredControlflowCodeGenerator.java | 3 + ...asmStructuredControlflowCodeGenerator.java | 25 ++++---- .../core/ir/ClassInitialization.java | 31 ++++++++++ .../mirkosertic/bytecoder/core/ir/Graph.java | 4 ++ .../mirkosertic/bytecoder/core/ir/Node.java | 4 ++ .../DeleteRedundantClassInitializations.java | 62 +++++++++++++++++++ .../core/optimizer/GlobalOptimizer.java | 19 ++++++ .../core/optimizer/Optimizations.java | 20 +++++- .../bytecoder/core/optimizer/STATS.md | 5 ++ .../bytecoder/core/parser/GraphParser.java | 62 +++++++++++++++---- 13 files changed, 228 insertions(+), 43 deletions(-) create mode 100644 core/src/main/java/de/mirkosertic/bytecoder/core/ir/ClassInitialization.java create mode 100644 core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/DeleteRedundantClassInitializations.java create mode 100644 core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/GlobalOptimizer.java diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/js/JSStructuredControlflowCodeGenerator.java b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/js/JSStructuredControlflowCodeGenerator.java index 48b55685f7..cb3e65e911 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/js/JSStructuredControlflowCodeGenerator.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/js/JSStructuredControlflowCodeGenerator.java @@ -32,6 +32,7 @@ import de.mirkosertic.bytecoder.core.ir.CMP; import de.mirkosertic.bytecoder.core.ir.Cast; import de.mirkosertic.bytecoder.core.ir.CaughtException; +import de.mirkosertic.bytecoder.core.ir.ClassInitialization; import de.mirkosertic.bytecoder.core.ir.Copy; import de.mirkosertic.bytecoder.core.ir.Div; import de.mirkosertic.bytecoder.core.ir.EnumValuesOf; @@ -282,6 +283,16 @@ private void writeExpression(final MethodInvocationExpression node) { } } + @Override + public void write(final ClassInitialization node) { + final ResolvedClass tc = compileUnit.findClass(node.type); + if (tc.requiresClassInitializer() && !node.skip) { + writeIndent(); + pw.print(generateClassName(node.type)); + pw.println(".$i;"); + } + } + private void writeExpressionDirectInvocation(final MethodInvocationExpression node) { final Type invocationTarget = Type.getObjectType(node.insnNode.owner); @@ -1734,9 +1745,6 @@ private void writeStatic(final MethodInvocation node) { final ResolvedClass resolvedClass = node.method.owner; pw.print(generateClassName(resolvedClass.type)); - if (resolvedClass.requiresClassInitializer()) { - pw.print(".$i"); - } pw.print("."); pw.print(generateMethodName(node.method.methodNode.name, node.method.methodType)); @@ -1754,12 +1762,7 @@ private void writeExpressionStaticInvocation(final MethodInvocationExpression no pw.print("("); - final ResolvedClass resolvedClass = node.method.owner; - pw.print(generateClassName(node.method.owner.type)); - if (resolvedClass.requiresClassInitializer()) { - pw.print(".$i"); - } pw.print("."); pw.print(generateMethodName(node.method.methodNode.name, node.method.methodType)); @@ -1896,15 +1899,9 @@ private void writeExpression(final TypeReference node) { if (type.getSort() == Type.ARRAY) { final ResolvedClass cl = compileUnit.resolveClass(Type.getType(Array.class), null); pw.print(generateClassName(cl.type)); - if (cl.requiresClassInitializer()) { - pw.print(".$i"); - } } else { final ResolvedClass cl = compileUnit.resolveClass(type, null); pw.print(generateClassName(cl.type)); - if (cl.requiresClassInitializer()) { - pw.print(".$i"); - } } } diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/opencl/OpenCLStructuredControlflowCodeGenerator.java b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/opencl/OpenCLStructuredControlflowCodeGenerator.java index 90ecdf5677..3bf759b00e 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/opencl/OpenCLStructuredControlflowCodeGenerator.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/opencl/OpenCLStructuredControlflowCodeGenerator.java @@ -26,6 +26,7 @@ import de.mirkosertic.bytecoder.core.ir.ArrayStore; import de.mirkosertic.bytecoder.core.ir.CMP; import de.mirkosertic.bytecoder.core.ir.Cast; +import de.mirkosertic.bytecoder.core.ir.ClassInitialization; import de.mirkosertic.bytecoder.core.ir.Copy; import de.mirkosertic.bytecoder.core.ir.Div; import de.mirkosertic.bytecoder.core.ir.FrameDebugInfo; @@ -268,6 +269,10 @@ private void writeExpression(final ReadInstanceField node) { } } + @Override + public void write(final ClassInitialization node) { + } + private void writeExpression(final ReadClassField node) { pw.print("("); diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/sequencer/Sequencer.java b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/sequencer/Sequencer.java index dcbd8e2c0d..08b9e723df 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/sequencer/Sequencer.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/sequencer/Sequencer.java @@ -17,6 +17,7 @@ import de.mirkosertic.bytecoder.core.ir.AbstractVar; import de.mirkosertic.bytecoder.core.ir.ArrayStore; +import de.mirkosertic.bytecoder.core.ir.ClassInitialization; import de.mirkosertic.bytecoder.core.ir.ControlTokenConsumer; import de.mirkosertic.bytecoder.core.ir.Copy; import de.mirkosertic.bytecoder.core.ir.FrameDebugInfo; @@ -165,9 +166,12 @@ private void visitDominationTreeOf(final ControlTokenConsumer startNode, final S codegenerator.write((MonitorExit) current); current = followUpProcessor.apply(current); } else if (current instanceof Unwind) { - // We are finished here codegenerator.write((Unwind) current); + // We are finished here current = null; + } else if (current instanceof ClassInitialization) { + codegenerator.write((ClassInitialization) current); + current = followUpProcessor.apply(current); } else if (current instanceof Nop) { current = followUpProcessor.apply(current); } else { diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/sequencer/StructuredControlflowCodeGenerator.java b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/sequencer/StructuredControlflowCodeGenerator.java index 7761067b9f..b358b88bae 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/sequencer/StructuredControlflowCodeGenerator.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/sequencer/StructuredControlflowCodeGenerator.java @@ -17,6 +17,7 @@ import de.mirkosertic.bytecoder.core.ir.AbstractVar; import de.mirkosertic.bytecoder.core.ir.ArrayStore; +import de.mirkosertic.bytecoder.core.ir.ClassInitialization; import de.mirkosertic.bytecoder.core.ir.Copy; import de.mirkosertic.bytecoder.core.ir.FrameDebugInfo; import de.mirkosertic.bytecoder.core.ir.Goto; @@ -76,6 +77,8 @@ public interface StructuredControlflowCodeGenerator { void write(ArrayStore node); + void write(ClassInitialization node); + void writeBreakTo(String label); void writeContinueTo(String label); diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/wasm/WasmStructuredControlflowCodeGenerator.java b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/wasm/WasmStructuredControlflowCodeGenerator.java index a448844602..a03da5bc01 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/wasm/WasmStructuredControlflowCodeGenerator.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/wasm/WasmStructuredControlflowCodeGenerator.java @@ -57,6 +57,7 @@ import de.mirkosertic.bytecoder.core.ir.CMP; import de.mirkosertic.bytecoder.core.ir.Cast; import de.mirkosertic.bytecoder.core.ir.CaughtException; +import de.mirkosertic.bytecoder.core.ir.ClassInitialization; import de.mirkosertic.bytecoder.core.ir.Copy; import de.mirkosertic.bytecoder.core.ir.Div; import de.mirkosertic.bytecoder.core.ir.EnumValuesOf; @@ -398,6 +399,16 @@ private void writeInterface(final MethodInvocation node) { activeLevel.activeFlow.voidCallIndirect(ft, indirectCallArgs, resolver); } + @Override + public void write(final ClassInitialization node) { + final ResolvedClass cl = compileUnit.findClass(node.type); + if (cl.requiresClassInitializer() && !node.skip) { + final String className = WasmHelpers.generateClassName(cl.type); + final Callable initFunction = ConstExpressions.weakFunctionReference(className + "_i"); + activeLevel.activeFlow.drop(ConstExpressions.call(initFunction, Collections.emptyList())); + } + } + private WasmValue toWasmValue(final This value) { final Local local = exportableFunction.localByLabel("thisref"); return ConstExpressions.getLocal(local); @@ -461,16 +472,10 @@ public static WasmValue createNewInstanceOf(final Type instanceType, final List initArgs = new ArrayList<>(); final String className = WasmHelpers.generateClassName(cl.type); - final WasmValue rttype; final Global global = module.getGlobals().globalsIndex().globalByLabel(className + "_cls"); - if (cl.requiresClassInitializer()) { - final Callable initFunction = ConstExpressions.weakFunctionReference(className + "_i"); - rttype = ConstExpressions.call(initFunction, Collections.emptyList()); - } else { - rttype = ConstExpressions.getGlobal(global); - } + final WasmValue rttype = ConstExpressions.getGlobal(global); initArgs.add( ConstExpressions.struct.get( @@ -1582,12 +1587,6 @@ private WasmValue toWasmValue(final ReadClassField value) { final ResolvedClass cl = field.owner; final StructType type = rtMappings.get(cl); final String className = WasmHelpers.generateClassName(cl.type); - if (cl.requiresClassInitializer()) { - final Callable initFunction = ConstExpressions.weakFunctionReference(className + "_i"); - return ConstExpressions.struct.get(type, - ConstExpressions.ref.cast(type, ConstExpressions.call(initFunction, Collections.emptyList())), - field.name); - } final Global global = module.getGlobals().globalsIndex().globalByLabel(className + "_cls"); return ConstExpressions.struct.get(type, ConstExpressions.getGlobal(global), field.name); diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/ir/ClassInitialization.java b/core/src/main/java/de/mirkosertic/bytecoder/core/ir/ClassInitialization.java new file mode 100644 index 0000000000..da3eea962b --- /dev/null +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/ir/ClassInitialization.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023 Mirko Sertic + * + * 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 de.mirkosertic.bytecoder.core.ir; + +import org.objectweb.asm.Type; + +public class ClassInitialization extends ControlTokenConsumer { + + public final Type type; + + public boolean skip; + + public ClassInitialization(final Type type) { + this.type = type; + } + + +} diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/ir/Graph.java b/core/src/main/java/de/mirkosertic/bytecoder/core/ir/Graph.java index 335ee0cd2e..a4d9ce984a 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/ir/Graph.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/ir/Graph.java @@ -432,6 +432,10 @@ public BootstrapMethod newBootstrapMethod(final Type methodType, final Type clas return (BootstrapMethod) register(new BootstrapMethod(methodType, className, methodName, kind)); } + public ClassInitialization newClassInitialization(final Type type) { + return (ClassInitialization) register(new ClassInitialization(type)); + } + public void remapDataFlow(final Node original, final Node newValue) { for (final Node n : nodes) { n.remapDataFlow(original, newValue); diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/ir/Node.java b/core/src/main/java/de/mirkosertic/bytecoder/core/ir/Node.java index 3879755040..5c2f8bc78d 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/ir/Node.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/ir/Node.java @@ -37,6 +37,10 @@ public void markAsDoBePruned() { tobepruned = true; } + public boolean isMarkedToBePruned() { + return tobepruned; + } + public String additionalDebugInfo() { return ""; } diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/DeleteRedundantClassInitializations.java b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/DeleteRedundantClassInitializations.java new file mode 100644 index 0000000000..fdfb9db0cc --- /dev/null +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/DeleteRedundantClassInitializations.java @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Mirko Sertic + * + * 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 de.mirkosertic.bytecoder.core.optimizer; + +import de.mirkosertic.bytecoder.core.backend.sequencer.DominatorTree; +import de.mirkosertic.bytecoder.core.ir.ClassInitialization; +import de.mirkosertic.bytecoder.core.ir.Graph; +import de.mirkosertic.bytecoder.core.ir.ResolvedClass; +import de.mirkosertic.bytecoder.core.ir.ResolvedMethod; +import de.mirkosertic.bytecoder.core.parser.CompileUnit; + +import java.util.List; +import java.util.stream.Collectors; + +public class DeleteRedundantClassInitializations implements GlobalOptimizer { + + private final NodePatternMatcher patternMatcher; + + public DeleteRedundantClassInitializations() { + patternMatcher = new NodePatternMatcher( + NodePredicates.ofType(ClassInitialization.class), + NodePredicates.singlePredWithForwardEdge(), + NodePredicates.singleSuccWithForwardEdge() + ); + } + + @Override + public boolean optimize(final CompileUnit compileUnit, final ResolvedMethod method) { + + final Graph g = method.methodBody; + + final DominatorTree dominatorTree = new DominatorTree(g); + final List initializers = g.nodes().stream().filter(t -> t instanceof ClassInitialization).map(t -> (ClassInitialization) t).collect(Collectors.toList()); + for (final ClassInitialization ci : initializers) { + final ResolvedClass rc = compileUnit.findClass(ci.type); + if (!rc.requiresClassInitializer()) { + ci.skip = true; + } + for (final ClassInitialization j : initializers) { + if (j != ci && ci.type.equals(j.type)) { + if (dominatorTree.dominates(ci, j)) { + j.skip = true; + } + } + } + } + return false; + } +} diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/GlobalOptimizer.java b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/GlobalOptimizer.java new file mode 100644 index 0000000000..531c5c01d7 --- /dev/null +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/GlobalOptimizer.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023 Mirko Sertic + * + * 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 de.mirkosertic.bytecoder.core.optimizer; + +public interface GlobalOptimizer extends Optimizer { +} diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/Optimizations.java b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/Optimizations.java index 3af0b5537a..ad87e6f049 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/Optimizations.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/Optimizations.java @@ -18,6 +18,10 @@ import de.mirkosertic.bytecoder.core.ir.ResolvedMethod; import de.mirkosertic.bytecoder.core.parser.CompileUnit; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + public enum Optimizations implements Optimizer { DISABLED(new Optimizer[] { }), @@ -27,7 +31,8 @@ public enum Optimizations implements Optimizer { new DeleteRedundantVariables(), new VariableIsConstant(), new VirtualToDirectInvocation(), - new DeleteCopyToUnusedPHI() + new DeleteCopyToUnusedPHI(), + new DeleteRedundantClassInitializations() }), ALL(new Optimizer[] { new DeleteUnusedConstants(), @@ -35,7 +40,8 @@ public enum Optimizations implements Optimizer { new DeleteRedundantVariables(), new VariableIsConstant(), new VirtualToDirectInvocation(), - new DeleteCopyToUnusedPHI() + new DeleteCopyToUnusedPHI(), + new DeleteRedundantClassInitializations() }), ; @@ -47,8 +53,16 @@ public enum Optimizations implements Optimizer { public boolean optimize(final CompileUnit compileUnit, final ResolvedMethod method) { boolean graphchanged = false; + final Set go = Arrays.stream(optimizers).filter(t -> t instanceof GlobalOptimizer).map(t -> (GlobalOptimizer) t).collect(Collectors.toSet()); for (final Optimizer o : optimizers) { - graphchanged = graphchanged | o.optimize(compileUnit, method); + if (!go.contains(o)) { + graphchanged = graphchanged | o.optimize(compileUnit, method); + } + } + if (!graphchanged) { + for (final GlobalOptimizer o : go) { + o.optimize(compileUnit, method); + } } return graphchanged; } diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/STATS.md b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/STATS.md index 81b1830a88..b3de60878d 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/STATS.md +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/optimizer/STATS.md @@ -29,3 +29,8 @@ JBOX2D JS Optimized 3069118 bytes LUA Wasm Optimized 557837 bytes LUA JS Optimized 2368451 bytes + +2023-05-11 JBOX2D Wasm Optimized 620892 bytes + JBOX2D JS Optimized 3097328 bytes + LUA Wasm Optimized 559307 bytes + LUA JS Optimized 2394748 bytes diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/parser/GraphParser.java b/core/src/main/java/de/mirkosertic/bytecoder/core/parser/GraphParser.java index b3ef7728c4..870a87e918 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/parser/GraphParser.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/parser/GraphParser.java @@ -22,6 +22,7 @@ import de.mirkosertic.bytecoder.core.ir.ArrayStore; import de.mirkosertic.bytecoder.core.ir.CMP; import de.mirkosertic.bytecoder.core.ir.Cast; +import de.mirkosertic.bytecoder.core.ir.ClassInitialization; import de.mirkosertic.bytecoder.core.ir.ControlTokenConsumer; import de.mirkosertic.bytecoder.core.ir.Copy; import de.mirkosertic.bytecoder.core.ir.EdgeType; @@ -811,11 +812,19 @@ private List parse_INVOKESTATIC(final ControlFlow currentFlow) { final ResolvedClass rc = compileUnit.resolveClass(targetClass, analysisStack); final ResolvedMethod rm = rc.resolveMethod(node.name, methodType, analysisStack); + final ClassInitialization classInit = graph.newClassInitialization(rc.type); + n = graph.newMethodInvocation(InvocationType.STATIC, node, rm); n.addIncomingData(incomingData); + + classInit.addControlFlowTo(StandardProjections.DEFAULT, n); + + graph.registerTranslation(node, new InstructionTranslation(currentState.frame, classInit, n)); + } else { + + graph.registerTranslation(node, new InstructionTranslation(currentState.frame, n)); } - graph.registerTranslation(node, new InstructionTranslation(currentState.frame, n)); newState = currentState.controlFlowsTo(n).withFrame(latest); graph.addFixup(new ControlFlowFixup(node, newState.frame, StandardProjections.DEFAULT, node.getNext())); @@ -831,18 +840,33 @@ private List parse_INVOKESTATIC(final ControlFlow currentFlow) { n = graph.newMethodInvocationExpression(InvocationType.STATIC, node, rm); n.addIncomingData(incomingData); - } - final Variable var = graph.newVariable(methodType.getReturnType()); - final Copy copy = graph.newCopy(); - copy.addIncomingData(n); - var.addIncomingData(copy); + final ClassInitialization classInit = graph.newClassInitialization(rc.type); - graph.registerTranslation(node, new InstructionTranslation(currentState.frame, copy)); + final Variable var = graph.newVariable(methodType.getReturnType()); + final Copy copy = graph.newCopy(); + copy.addIncomingData(n); + var.addIncomingData(copy); - newState = currentState.controlFlowsTo(copy).withFrame(latest.pushToStack(var)); - graph.addFixup(new ControlFlowFixup(node, newState.frame, StandardProjections.DEFAULT, node.getNext())); + classInit.addControlFlowTo(StandardProjections.DEFAULT, copy); + + graph.registerTranslation(node, new InstructionTranslation(currentState.frame, classInit, copy)); + newState = currentState.controlFlowsTo(copy).withFrame(latest.pushToStack(var)); + graph.addFixup(new ControlFlowFixup(node, newState.frame, StandardProjections.DEFAULT, node.getNext())); + + } else { + + final Variable var = graph.newVariable(methodType.getReturnType()); + final Copy copy = graph.newCopy(); + copy.addIncomingData(n); + var.addIncomingData(copy); + + graph.registerTranslation(node, new InstructionTranslation(currentState.frame, copy)); + + newState = currentState.controlFlowsTo(copy).withFrame(latest.pushToStack(var)); + graph.addFixup(new ControlFlowFixup(node, newState.frame, StandardProjections.DEFAULT, node.getNext())); + } } return Collections.singletonList(currentFlow.continueWith(node.getNext(), newState)); @@ -1968,12 +1992,17 @@ private List parse_NEW(final ControlFlow currentFlow) { final New n = graph.newNew(type); n.addIncomingData(typeReference); + final ClassInitialization classInitialization = graph.newClassInitialization(type); + final Variable variable = graph.newVariable(type); final Copy copy = graph.newCopy(); copy.addIncomingData(n); variable.addIncomingData(copy); - graph.registerTranslation(node, new InstructionTranslation(currentState.frame, copy)); + + classInitialization.addControlFlowTo(StandardProjections.DEFAULT, copy); + + graph.registerTranslation(node, new InstructionTranslation(currentState.frame, classInitialization, copy)); final Frame newFrame = currentState.frame.pushToStack(variable); @@ -2132,11 +2161,16 @@ private List parse_GETSTATICFIELD(final ControlFlow currentFlow) { final ReadClassField field = graph.newClassFieldExpression(t, resolvedField); field.addIncomingData(graph.newTypeReference(targetClass.type)); final Variable target = graph.newVariable(t); + + final ClassInitialization classInit = graph.newClassInitialization(targetClass.type); + final Copy copy = graph.newCopy(); copy.addIncomingData(field); target.addIncomingData(copy); - graph.registerTranslation(node, new InstructionTranslation(currentState.frame, copy)); + classInit.addControlFlowTo(StandardProjections.DEFAULT, copy); + + graph.registerTranslation(node, new InstructionTranslation(currentState.frame, classInit, copy)); final GraphParserState newState = currentState.controlFlowsTo(copy).withFrame(currentState.frame.pushToStack(target)); graph.addFixup(new ControlFlowFixup(node, newState.frame, StandardProjections.DEFAULT, node.getNext())); @@ -2180,10 +2214,14 @@ private List parse_PUTSTATICFIELD(final ControlFlow currentFlow) { final SetClassField setfield = graph.newSetClassField(resolvedField); + final ClassInitialization classInit = graph.newClassInitialization(targetClass.type); + setfield.addIncomingData(valuePop.value); graph.newTypeReference(targetClass.type).addIncomingData(setfield); - graph.registerTranslation(node, new InstructionTranslation(currentState.frame, setfield)); + classInit.addControlFlowTo(StandardProjections.DEFAULT, setfield); + + graph.registerTranslation(node, new InstructionTranslation(currentState.frame, classInit, setfield)); final GraphParserState newState = currentState.controlFlowsTo(setfield).withFrame(valuePop.newFrame); graph.addFixup(new ControlFlowFixup(node, newState.frame, StandardProjections.DEFAULT, node.getNext()));