1 /*
   2  * Copyright (c) 2019, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.jvm;
  27 
  28 import com.sun.tools.javac.code.Type;
  29 import com.sun.tools.javac.code.Types;
  30 import com.sun.tools.javac.code.Types.UniqueType;
  31 import com.sun.tools.javac.util.List;
  32 import com.sun.tools.javac.util.Name;
  33 import com.sun.tools.javac.util.Pair;
  34 
  35 import java.util.Objects;
  36 import java.util.stream.Stream;
  37 
  38 /**
  39  * This interface models all javac entities that can be used to represent constant pool entries.
  40  * A pool constant entity must (i) be associated with a constant pool entry tag and have a function
  41  * which generates a key for the desired pool entry (so as to avoid duplicate entries when writing the
  42  * constant pool).
  43  */
  44 public interface PoolConstant {
  45 
  46     /**
  47      * The constant pool entry key.
  48      */
  49     default Object poolKey(Types types) { return this; }
  50 
  51     /**
  52      * The constant pool entry tag.
  53      */
  54     int poolTag();
  55 
  56     /**
  57      * The root of pool constants that can be loaded (e.g. with {@code ldc}, or appear as static
  58      * arguments to a bootstrap method.
  59      */
  60     interface LoadableConstant extends PoolConstant {
  61 
  62         /**
  63          * Create a pool constant describing a given {@code int} value.
  64          */
  65         static LoadableConstant Int(int i) {
  66             return new BasicConstant(ClassFile.CONSTANT_Integer, i);
  67         }
  68 
  69         /**
  70          * Create a pool constant describing a given {@code float} value.
  71          */
  72         static LoadableConstant Float(float f) {
  73             return new BasicConstant(ClassFile.CONSTANT_Float, f);
  74         }
  75 
  76         /**
  77          * Create a pool constant describing a given {@code long} value.
  78          */
  79         static LoadableConstant Long(long l) {
  80             return new BasicConstant(ClassFile.CONSTANT_Long, l);
  81         }
  82 
  83         /**
  84          * Create a pool constant describing a given {@code double} value.
  85          */
  86         static LoadableConstant Double(double d) {
  87             return new BasicConstant(ClassFile.CONSTANT_Double, d);
  88         }
  89 
  90         /**
  91          * Create a pool constant describing a given {@code String} value.
  92          */
  93         static LoadableConstant String(String s) {
  94             return new BasicConstant(ClassFile.CONSTANT_String, s);
  95         }
  96 
  97         /**
  98          * This class models a pool constant of given basic type, one of {@code int}, {@code float},
  99          * {@code long}, {@code double} or {@code String}.
 100          */
 101         class BasicConstant implements LoadableConstant {
 102             int tag;
 103             Object data;
 104 
 105             private BasicConstant(int tag, Object data) {
 106                 this.tag = tag;
 107                 this.data = data;
 108             }
 109 
 110             @Override
 111             public int poolTag() {
 112                 return tag;
 113             }
 114 
 115             @Override
 116             public Object poolKey(Types types) {
 117                 return data;
 118             }
 119         }
 120     }
 121 
 122     /**
 123      * This interface models a dynamic pool constant (either of kind {@code InvokeDynamic} or
 124      * {@code ConstantDynamic}). In addition to the functionalities provided by the base interface,
 125      * a dynamic pool constant must expose its dynamic type, bootstrap method and static argument list.
 126      * Finally, a dynamic constant must have a way to compute a bootstrap method key - that is,
 127      * a unique key for the bootstrap method entry it refers to, to avoid duplicates when writing
 128      * the {@code BootstrapMethods} attribute.
 129      */
 130     interface Dynamic extends PoolConstant {
 131 
 132         /**
 133          * The dynamic constant's dynamic type.
 134          */
 135         PoolConstant dynamicType();
 136 
 137         /**
 138          * The dynamic constant's static argument list.
 139          */
 140         LoadableConstant[] staticArgs();
 141 
 142         /**
 143          * The dynamic constant's bootstrap method.
 144          */
 145         LoadableConstant bootstrapMethod();
 146 
 147         default BsmKey bsmKey(Types types) {
 148             return new BsmKey(types, bootstrapMethod(), staticArgs());
 149         }
 150 
 151         @Override
 152         default Object poolKey(Types types) {
 153             return new Pair<>(bsmKey(types), dynamicType().poolKey(types));
 154         }
 155 
 156         /**
 157          * A class modelling a bootstrap method key.
 158          */
 159         class BsmKey {
 160             /**
 161              * The key's bootstrap method constant.
 162              */
 163             public final LoadableConstant bsm;
 164 
 165             /**
 166              * The key's static argument list.
 167              */
 168             public final LoadableConstant[] staticArgs;
 169 
 170             private final Object bsmKey;
 171             private final List<?> staticArgKeys;
 172 
 173             private BsmKey(Types types, LoadableConstant bsm, LoadableConstant[] staticArgs) {
 174                 this.bsm = bsm;
 175                 this.bsmKey = bsm.poolKey(types);
 176                 this.staticArgs = staticArgs;
 177                 this.staticArgKeys = Stream.of(staticArgs)
 178                         .map(p -> p.poolKey(types))
 179                         .collect(List.collector());
 180             }
 181 
 182             @Override
 183             public int hashCode() {
 184                 return bsmKey.hashCode() +
 185                         staticArgKeys.hashCode();
 186             }
 187 
 188             @Override
 189             public boolean equals(Object obj) {
 190                 if (obj instanceof BsmKey) {
 191                     BsmKey other = (BsmKey)obj;
 192                     return Objects.equals(bsmKey, other.bsmKey) &&
 193                             Objects.equals(staticArgKeys, other.staticArgKeys);
 194                 } else {
 195                     return false;
 196                 }
 197             }
 198         }
 199     }
 200 
 201     /**
 202      * A pool constant implementation describing a name and type pool entry.
 203      */
 204     final class NameAndType implements PoolConstant {
 205 
 206         final Name name;
 207         final Type type;
 208 
 209         NameAndType(Name name, Type type) {
 210             this.name = name;
 211             this.type = type;
 212         }
 213 
 214         @Override
 215         public int poolTag() {
 216             return ClassFile.CONSTANT_NameandType;
 217         }
 218 
 219         @Override
 220         public Object poolKey(Types types) {
 221             return new Pair<>(name, new UniqueType(type, types));
 222         }
 223     }
 224 }