1 /*
   2  * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.lir.dfa;
  24 
  25 import static jdk.vm.ci.code.ValueUtil.asRegister;
  26 import static jdk.vm.ci.code.ValueUtil.asStackSlot;
  27 import static jdk.vm.ci.code.ValueUtil.isRegister;
  28 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
  29 
  30 import java.util.EnumSet;
  31 import java.util.HashSet;
  32 import java.util.Objects;
  33 import java.util.Set;
  34 
  35 import org.graalvm.compiler.core.common.LIRKind;
  36 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
  37 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
  38 import org.graalvm.compiler.lir.ValueConsumer;
  39 import org.graalvm.compiler.lir.framemap.FrameMap;
  40 import org.graalvm.compiler.lir.framemap.ReferenceMapBuilder;
  41 import org.graalvm.compiler.lir.util.IndexedValueMap;
  42 import org.graalvm.compiler.lir.util.ValueSet;
  43 
  44 import jdk.vm.ci.meta.Value;
  45 
  46 final class RegStackValueSet extends ValueSet<RegStackValueSet> {
  47 
  48     private final FrameMap frameMap;
  49     private final IndexedValueMap registers;
  50     private final IndexedValueMap stack;
  51     private Set<Value> extraStack;
  52 
  53     RegStackValueSet(FrameMap frameMap) {
  54         this.frameMap = frameMap;
  55         registers = new IndexedValueMap();
  56         stack = new IndexedValueMap();
  57     }
  58 
  59     private RegStackValueSet(FrameMap frameMap, RegStackValueSet s) {
  60         this.frameMap = frameMap;
  61         registers = new IndexedValueMap(s.registers);
  62         stack = new IndexedValueMap(s.stack);
  63         if (s.extraStack != null) {
  64             extraStack = new HashSet<>(s.extraStack);
  65         }
  66     }
  67 
  68     @Override
  69     public RegStackValueSet copy() {
  70         return new RegStackValueSet(frameMap, this);
  71     }
  72 
  73     @Override
  74     public void put(Value v) {
  75         if (!shouldProcessValue(v)) {
  76             return;
  77         }
  78         if (isRegister(v)) {
  79             int index = asRegister(v).number;
  80             registers.put(index, v);
  81         } else if (isStackSlot(v)) {
  82             int index = frameMap.offsetForStackSlot(asStackSlot(v));
  83             assert index >= 0;
  84             if (index % 4 == 0) {
  85                 stack.put(index / 4, v);
  86             } else {
  87                 if (extraStack == null) {
  88                     extraStack = new HashSet<>();
  89                 }
  90                 extraStack.add(v);
  91             }
  92         }
  93     }
  94 
  95     @Override
  96     public void putAll(RegStackValueSet v) {
  97         registers.putAll(v.registers);
  98         stack.putAll(v.stack);
  99         if (v.extraStack != null) {
 100             if (extraStack == null) {
 101                 extraStack = new HashSet<>();
 102             }
 103             extraStack.addAll(v.extraStack);
 104         }
 105     }
 106 
 107     @Override
 108     public void remove(Value v) {
 109         if (!shouldProcessValue(v)) {
 110             return;
 111         }
 112         if (isRegister(v)) {
 113             int index = asRegister(v).number;
 114             registers.put(index, null);
 115         } else if (isStackSlot(v)) {
 116             int index = frameMap.offsetForStackSlot(asStackSlot(v));
 117             assert index >= 0;
 118             if (index % 4 == 0) {
 119                 stack.put(index / 4, null);
 120             } else if (extraStack != null) {
 121                 extraStack.remove(v);
 122             }
 123         }
 124     }
 125 
 126     @Override
 127     public boolean equals(Object obj) {
 128         if (obj instanceof RegStackValueSet) {
 129             RegStackValueSet other = (RegStackValueSet) obj;
 130             return registers.equals(other.registers) && stack.equals(other.stack) && Objects.equals(extraStack, other.extraStack);
 131         } else {
 132             return false;
 133         }
 134     }
 135 
 136     @Override
 137     public int hashCode() {
 138         throw new UnsupportedOperationException();
 139     }
 140 
 141     private static boolean shouldProcessValue(Value v) {
 142         /*
 143          * We always process registers because we have to track the largest register size that is
 144          * alive across safepoints in order to save and restore them.
 145          */
 146         return isRegister(v) || !LIRKind.isValue(v);
 147     }
 148 
 149     public void addLiveValues(ReferenceMapBuilder refMap) {
 150         ValueConsumer addLiveValue = new ValueConsumer() {
 151             @Override
 152             public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
 153                 refMap.addLiveValue(value);
 154             }
 155         };
 156         registers.visitEach(null, null, null, addLiveValue);
 157         stack.visitEach(null, null, null, addLiveValue);
 158         if (extraStack != null) {
 159             for (Value v : extraStack) {
 160                 refMap.addLiveValue(v);
 161             }
 162         }
 163     }
 164 }