001/* 002 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.hotspot.nodes; 024 025import jdk.internal.jvmci.common.*; 026import jdk.internal.jvmci.hotspot.*; 027import jdk.internal.jvmci.hotspot.HotSpotVMConfig.*; 028import jdk.internal.jvmci.meta.*; 029 030import com.oracle.graal.compiler.common.type.*; 031import com.oracle.graal.graph.*; 032import com.oracle.graal.graph.spi.*; 033import com.oracle.graal.hotspot.*; 034import com.oracle.graal.hotspot.nodes.type.*; 035import com.oracle.graal.nodeinfo.*; 036import com.oracle.graal.nodes.*; 037import com.oracle.graal.nodes.calc.*; 038import com.oracle.graal.nodes.spi.*; 039import com.oracle.graal.nodes.type.*; 040 041/** 042 * Compress or uncompress an oop or metaspace pointer. 043 */ 044@NodeInfo(nameTemplate = "{p#op/s}") 045public final class CompressionNode extends UnaryNode implements ConvertNode, LIRLowerable { 046 047 public static final NodeClass<CompressionNode> TYPE = NodeClass.create(CompressionNode.class); 048 049 public enum CompressionOp { 050 Compress, 051 Uncompress 052 } 053 054 protected final CompressionOp op; 055 protected final CompressEncoding encoding; 056 057 public CompressionNode(CompressionOp op, ValueNode input, CompressEncoding encoding) { 058 super(TYPE, mkStamp(op, input.stamp(), encoding), input); 059 this.op = op; 060 this.encoding = encoding; 061 } 062 063 @Override 064 public boolean inferStamp() { 065 return updateStamp(mkStamp(op, getValue().stamp(), encoding)); 066 } 067 068 public static CompressionNode compress(ValueNode input, CompressEncoding encoding) { 069 return input.graph().unique(new CompressionNode(CompressionOp.Compress, input, encoding)); 070 } 071 072 public static CompressionNode compressNoUnique(ValueNode input, CompressEncoding encoding) { 073 return new CompressionNode(CompressionOp.Compress, input, encoding); 074 } 075 076 public static CompressionNode uncompress(ValueNode input, CompressEncoding encoding) { 077 return input.graph().unique(new CompressionNode(CompressionOp.Uncompress, input, encoding)); 078 } 079 080 private static Constant compress(Constant c, CompressEncoding encoding) { 081 if (JavaConstant.NULL_POINTER.equals(c)) { 082 return HotSpotCompressedNullConstant.COMPRESSED_NULL; 083 } else if (c instanceof HotSpotObjectConstant) { 084 return ((HotSpotObjectConstant) c).compress(); 085 } else if (c instanceof HotSpotMetaspaceConstant) { 086 return ((HotSpotMetaspaceConstant) c).compress(encoding); 087 } else { 088 throw JVMCIError.shouldNotReachHere("invalid constant input for compress op: " + c); 089 } 090 } 091 092 private static Constant uncompress(Constant c, CompressEncoding encoding) { 093 if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { 094 return JavaConstant.NULL_POINTER; 095 } else if (c instanceof HotSpotObjectConstant) { 096 return ((HotSpotObjectConstant) c).uncompress(); 097 } else if (c instanceof HotSpotMetaspaceConstant) { 098 return ((HotSpotMetaspaceConstant) c).uncompress(encoding); 099 } else { 100 throw JVMCIError.shouldNotReachHere("invalid constant input for uncompress op: " + c); 101 } 102 } 103 104 @Override 105 public Constant convert(Constant c, ConstantReflectionProvider constantReflection) { 106 switch (op) { 107 case Compress: 108 return compress(c, encoding); 109 case Uncompress: 110 return uncompress(c, encoding); 111 default: 112 throw JVMCIError.shouldNotReachHere(); 113 } 114 } 115 116 @Override 117 public Constant reverse(Constant c, ConstantReflectionProvider constantReflection) { 118 switch (op) { 119 case Compress: 120 return uncompress(c, encoding); 121 case Uncompress: 122 return compress(c, encoding); 123 default: 124 throw JVMCIError.shouldNotReachHere(); 125 } 126 } 127 128 @Override 129 public boolean isLossless() { 130 return true; 131 } 132 133 private static Stamp mkStamp(CompressionOp op, Stamp input, CompressEncoding encoding) { 134 switch (op) { 135 case Compress: 136 if (input instanceof ObjectStamp) { 137 // compressed oop 138 return NarrowOopStamp.compressed((ObjectStamp) input, encoding); 139 } else if (input instanceof KlassPointerStamp) { 140 // compressed klass pointer 141 return ((KlassPointerStamp) input).compressed(encoding); 142 } 143 break; 144 case Uncompress: 145 if (input instanceof NarrowOopStamp) { 146 // oop 147 assert encoding.equals(((NarrowOopStamp) input).getEncoding()); 148 return ((NarrowOopStamp) input).uncompressed(); 149 } else if (input instanceof KlassPointerStamp) { 150 // metaspace pointer 151 assert encoding.equals(((KlassPointerStamp) input).getEncoding()); 152 return ((KlassPointerStamp) input).uncompressed(); 153 } 154 break; 155 } 156 throw JVMCIError.shouldNotReachHere(String.format("Unexpected input stamp %s", input)); 157 } 158 159 public CompressionOp getOp() { 160 return op; 161 } 162 163 public CompressEncoding getEncoding() { 164 return encoding; 165 } 166 167 @Override 168 public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { 169 if (forValue.isConstant()) { 170 return ConstantNode.forConstant(stamp(), convert(forValue.asConstant(), tool.getConstantReflection()), tool.getMetaAccess()); 171 } else if (forValue instanceof CompressionNode) { 172 CompressionNode other = (CompressionNode) forValue; 173 if (op != other.op && encoding.equals(other.encoding)) { 174 return other.getValue(); 175 } 176 } 177 return this; 178 } 179 180 @Override 181 public void generate(NodeLIRBuilderTool gen) { 182 HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool(); 183 boolean nonNull; 184 if (getValue().stamp() instanceof AbstractObjectStamp) { 185 nonNull = StampTool.isPointerNonNull(getValue().stamp()); 186 } else { 187 // metaspace pointers are never null 188 nonNull = true; 189 } 190 191 Value result; 192 switch (op) { 193 case Compress: 194 result = hsGen.emitCompress(gen.operand(getValue()), encoding, nonNull); 195 break; 196 case Uncompress: 197 result = hsGen.emitUncompress(gen.operand(getValue()), encoding, nonNull); 198 break; 199 default: 200 throw JVMCIError.shouldNotReachHere(); 201 } 202 gen.setResult(this, result); 203 } 204 205 @NodeIntrinsic 206 public static native Object compression(@ConstantNodeParameter CompressionOp op, Object object, @ConstantNodeParameter CompressEncoding encoding); 207}