From 3ed75a97d4483c99511cd71d9ea29a37853a4501 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 9 Jul 2019 14:41:39 +0300 Subject: [PATCH] C: fix insertion of shadow stack instructions --- .../lowlevel/GCShadowStackContributor.java | 76 +--------- .../model/lowlevel/SpilledPhisFinder.java | 131 ++++++++++++++++++ 2 files changed, 138 insertions(+), 69 deletions(-) create mode 100644 core/src/main/java/org/teavm/model/lowlevel/SpilledPhisFinder.java diff --git a/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java b/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java index bf716e58f..134ae28f8 100644 --- a/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java +++ b/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java @@ -22,14 +22,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; import org.teavm.common.DisjointSet; import org.teavm.common.DominatorTree; import org.teavm.common.Graph; @@ -102,14 +99,11 @@ public class GCShadowStackContributor { // If a variable is spilled to stack, then phi which takes this variable as input also spilled to stack // If all of phi inputs are spilled to stack, then we don't need to insert spilling instruction // for this phi. - List> destinationPhis = getDestinationPhis(program); - int[] inputCount = getInputCount(program); - boolean[] autoSpilled = new boolean[spilled.length]; - for (int i = 0; i < spilled.length; ++i) { - findAutoSpilledPhis(spilled, destinationPhis, inputCount, autoSpilled, i); - } + Graph cfg = ProgramUtils.buildControlFlowGraph(program); + DominatorTree dom = GraphUtils.buildDominatorTree(cfg); + boolean[] autoSpilled = new SpilledPhisFinder(liveInInformation, dom, program).find(); - List> liveInStores = reduceGCRootStores(program, usedColors, liveInInformation, + List> liveInStores = reduceGCRootStores(dom, program, usedColors, liveInInformation, colors, autoSpilled); putLiveInGCRoots(program, liveInStores); @@ -131,26 +125,6 @@ public class GCShadowStackContributor { return variableClasses.pack(program.variableCount()); } - private void findAutoSpilledPhis(boolean[] spilled, List> destinationPhis, int[] inputCount, - boolean[] autoSpilled, int i) { - if (!spilled[i]) { - return; - } - Set phis = destinationPhis.get(i); - if (phis != null) { - for (Phi phi : destinationPhis.get(i)) { - int destination = phi.getReceiver().getIndex(); - autoSpilled[destination] = --inputCount[destination] == 0; - if (!spilled[destination]) { - spilled[destination] = true; - if (i > destination) { - findAutoSpilledPhis(spilled, destinationPhis, inputCount, autoSpilled, destination); - } - } - } - } - } - private List> findCallSiteLiveIns(Program program, MethodReader method) { boolean[] nativePointers = nativePointerFinder.findNativePointers(method.getReference(), program); @@ -243,41 +217,7 @@ public class GCShadowStackContributor { return affectedVariables; } - private List> getDestinationPhis(Program program) { - List> destinationPhis = new ArrayList<>(); - destinationPhis.addAll(Collections.nCopies(program.variableCount(), null)); - - for (int i = 0; i < program.basicBlockCount(); ++i) { - BasicBlock block = program.basicBlockAt(i); - for (Phi phi : block.getPhis()) { - for (Incoming incoming : phi.getIncomings()) { - Set phis = destinationPhis.get(incoming.getValue().getIndex()); - if (phis == null) { - phis = new LinkedHashSet<>(); - destinationPhis.set(incoming.getValue().getIndex(), phis); - } - phis.add(phi); - } - } - } - - return destinationPhis; - } - - private int[] getInputCount(Program program) { - int[] inputCount = new int[program.variableCount()]; - - for (int i = 0; i < program.basicBlockCount(); ++i) { - BasicBlock block = program.basicBlockAt(i); - for (Phi phi : block.getPhis()) { - inputCount[phi.getReceiver().getIndex()] = phi.getIncomings().size(); - } - } - - return inputCount; - } - - private List> reduceGCRootStores(Program program, int usedColors, + private List> reduceGCRootStores(DominatorTree dom, Program program, int usedColors, List> liveInInformation, int[] colors, boolean[] autoSpilled) { class Step { private final int node; @@ -292,9 +232,7 @@ public class GCShadowStackContributor { slotsToUpdate.add(new LinkedHashMap<>()); } - Graph cfg = ProgramUtils.buildControlFlowGraph(program); - DominatorTree dom = GraphUtils.buildDominatorTree(cfg); - Graph domGraph = GraphUtils.buildDominatorGraph(dom, cfg.size()); + Graph domGraph = GraphUtils.buildDominatorGraph(dom, program.basicBlockCount()); Step[] stack = new Step[program.basicBlockCount() * 2]; int head = 0; @@ -374,7 +312,7 @@ public class GCShadowStackContributor { Instruction[] callSiteLocations = updatesByIndex.keySet().toArray(new Instruction[0]); ObjectIntMap instructionIndexes = getInstructionIndexes(block); Arrays.sort(callSiteLocations, Comparator.comparing(instructionIndexes::get)); - for (Instruction callSiteLocation : updatesByIndex.keySet()) { + for (Instruction callSiteLocation : callSiteLocations) { int[] updates = updatesByIndex.get(callSiteLocation); storeLiveIns(block, callSiteLocation, updates); } diff --git a/core/src/main/java/org/teavm/model/lowlevel/SpilledPhisFinder.java b/core/src/main/java/org/teavm/model/lowlevel/SpilledPhisFinder.java new file mode 100644 index 000000000..9d19320ff --- /dev/null +++ b/core/src/main/java/org/teavm/model/lowlevel/SpilledPhisFinder.java @@ -0,0 +1,131 @@ +/* + * Copyright 2019 konsoletyper. + * + * 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.model.lowlevel; + +import com.carrotsearch.hppc.IntHashSet; +import com.carrotsearch.hppc.IntSet; +import java.util.Arrays; +import java.util.BitSet; +import java.util.List; +import java.util.Map; +import org.teavm.common.DominatorTree; +import org.teavm.model.BasicBlock; +import org.teavm.model.Incoming; +import org.teavm.model.Instruction; +import org.teavm.model.Phi; +import org.teavm.model.Program; + +class SpilledPhisFinder { + private static final byte VISITING = 1; + private static final byte VISITED = 2; + private DominatorTree dom; + boolean[] autoSpilled; + byte[] status; + int[][] variableSpilledBlocks; + Phi[] definingPhis; + int variableCount; + + SpilledPhisFinder(List> liveInInformation, DominatorTree dom, Program program) { + this.dom = dom; + variableCount = program.variableCount(); + autoSpilled = new boolean[variableCount]; + status = new byte[variableCount]; + variableSpilledBlocks = variableSpilledBlocks(liveInInformation, variableCount); + definingPhis = findPhis(program); + } + + private static int[][] variableSpilledBlocks(List> liveInInformation, int count) { + IntSet[] builder = new IntSet[count]; + for (int b = 0; b < liveInInformation.size(); b++) { + Map blockLiveIn = liveInInformation.get(b); + for (BitSet liveVarsSet : blockLiveIn.values()) { + for (int v = liveVarsSet.nextSetBit(0); v >= 0; v = liveVarsSet.nextSetBit(v + 1)) { + if (builder[v] == null) { + builder[v] = new IntHashSet(); + } + builder[v].add(b); + } + } + } + + int[][] result = new int[builder.length][]; + for (int v = 0; v < result.length; ++v) { + if (builder[v] != null) { + result[v] = builder[v].toArray(); + Arrays.sort(result[v]); + } + } + return result; + } + + private static Phi[] findPhis(Program program) { + Phi[] result = new Phi[program.variableCount()]; + for (BasicBlock block : program.getBasicBlocks()) { + for (Phi phi : block.getPhis()) { + result[phi.getReceiver().getIndex()] = phi; + } + } + return result; + } + + boolean[] find() { + for (int v = 0; v < variableCount; ++v) { + isAutoSpilled(v); + } + return autoSpilled; + } + + private boolean isAutoSpilled(int v) { + if (status[v] == VISITED) { + return autoSpilled[v]; + } + + if (status[v] == VISITING) { + return false; + } + + Phi definingPhi = definingPhis[v]; + if (definingPhi == null) { + status[v] = VISITED; + return false; + } + + status[v] = VISITING; + + boolean result = true; + for (Incoming incoming : definingPhi.getIncomings()) { + if (!isAutoSpilled(incoming.getValue().getIndex())) { + int[] spilledAt = variableSpilledBlocks[incoming.getValue().getIndex()]; + result = false; + if (spilledAt != null) { + for (int spilledAtBlock : spilledAt) { + if (dom.dominates(spilledAtBlock, incoming.getSource().getIndex())) { + result = true; + break; + } + } + } + if (!result) { + break; + } + } + } + + autoSpilled[v] = result; + status[v] = VISITED; + return result; + } +}