1 /*
   2  * Copyright (c) 1999, 2018, 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.Symbol;
  29 import com.sun.tools.javac.code.Symbol.*;
  30 import com.sun.tools.javac.code.TypeTag;
  31 import com.sun.tools.javac.code.Type;
  32 import com.sun.tools.javac.code.Types;
  33 import com.sun.tools.javac.code.Types.UniqueType;
  34 
  35 import com.sun.tools.javac.util.ArrayUtils;
  36 import com.sun.tools.javac.util.Assert;
  37 import com.sun.tools.javac.util.Filter;
  38 import com.sun.tools.javac.util.Name;
  39 
  40 import java.util.*;
  41 
  42 import com.sun.tools.javac.code.Symtab;
  43 import com.sun.tools.javac.util.DefinedBy;
  44 import com.sun.tools.javac.util.DefinedBy.Api;
  45 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  46 import com.sun.tools.javac.util.Log;
  47 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
  48 
  49 import static com.sun.tools.javac.code.Flags.INTERFACE;
  50 import static com.sun.tools.javac.code.Kinds.*;
  51 import static com.sun.tools.javac.code.Kinds.Kind.*;
  52 
  53 /** An internal structure that corresponds to the constant pool of a classfile.
  54  *
  55  *  <p><b>This is NOT part of any supported API.
  56  *  If you write code that depends on this, you do so at your own risk.
  57  *  This code and its internal interfaces are subject to change or
  58  *  deletion without notice.</b>
  59  */
  60 public class Pool {
  61 
  62     public static final int MAX_ENTRIES = 0xFFFF;
  63     public static final int MAX_STRING_LENGTH = 0xFFFF;
  64 
  65     /** Index of next constant to be entered.
  66      */
  67     int pp;
  68 
  69     /** The initial pool buffer.
  70      */
  71     Object[] pool;
  72 
  73     /** A hashtable containing all constants in the pool.
  74      */
  75     Map<Object,Integer> indices;
  76 
  77     Types types;
  78 
  79     /** Construct a pool with given number of elements and element array.
  80      */
  81     public Pool(int pp, Object[] pool, Types types) {
  82         this.pp = pp;
  83         this.pool = pool;
  84         this.types = types;
  85         this.indices = new HashMap<>(pool.length);
  86         for (int i = 1; i < pp; i++) {
  87             if (pool[i] != null) indices.put(pool[i], i);
  88         }
  89     }
  90 
  91     /** Construct an empty pool.
  92      */
  93     public Pool(Types types) {
  94         this(1, new Object[64], types);
  95     }
  96 
  97     /** Return the number of entries in the constant pool.
  98      */
  99     public int numEntries() {
 100         return pp;
 101     }
 102 
 103     /** Remove everything from this pool.
 104      */
 105     public void reset() {
 106         pp = 1;
 107         indices.clear();
 108     }
 109 
 110     /** Place an object in the pool, unless it is already there.
 111      *  If object is a symbol also enter its owner unless the owner is a
 112      *  package.  Return the object's index in the pool.
 113      */
 114     public int put(Object value) {
 115         value = makePoolValue(value);
 116         Assert.check(!(value instanceof Type.TypeVar));
 117         Assert.check(!(value instanceof Types.UniqueType &&
 118                        ((UniqueType) value).type instanceof Type.TypeVar));
 119         Integer index = indices.get(value);
 120         if (index == null) {
 121             index = pp;
 122             indices.put(value, index);
 123             pool = ArrayUtils.ensureCapacity(pool, pp);
 124             pool[pp++] = value;
 125             if (value instanceof Long || value instanceof Double) {
 126                 pool = ArrayUtils.ensureCapacity(pool, pp);
 127                 pool[pp++] = null;
 128             }
 129         }
 130         return index.intValue();
 131     }
 132 
 133     Object makePoolValue(Object o) {
 134         if (o instanceof DynamicMethodSymbol) {
 135             return new DynamicMethod((DynamicMethodSymbol)o, types);
 136         } else if (o instanceof DynamicVarSymbol) {
 137             return new Pool.DynamicVariable((DynamicVarSymbol)o, types);
 138         } else if (o instanceof MethodSymbol) {
 139             return new Method((MethodSymbol)o, types);
 140         } else if (o instanceof VarSymbol) {
 141             return new Variable((VarSymbol)o, types);
 142         } else if (o instanceof Type) {
 143             Type t = (Type)o;
 144             // ClassRefs can come from ClassSymbols or from Types.
 145             // Return the symbol for these types to avoid duplicates
 146             // in the constant pool
 147             if (t.hasTag(TypeTag.CLASS))
 148                 return t.tsym;
 149             else
 150                 return new UniqueType(t, types);
 151         } else {
 152             return o;
 153         }
 154     }
 155 
 156     /** Return the given object's index in the pool,
 157      *  or -1 if object is not in there.
 158      */
 159     public int get(Object o) {
 160         Integer n = indices.get(o);
 161         return n == null ? -1 : n.intValue();
 162     }
 163 
 164     static class Method extends DelegatedSymbol<MethodSymbol> {
 165         UniqueType uniqueType;
 166         Method(MethodSymbol m, Types types) {
 167             super(m);
 168             this.uniqueType = new UniqueType(m.type, types);
 169         }
 170         @DefinedBy(Api.LANGUAGE_MODEL)
 171         public boolean equals(Object any) {
 172             if (!(any instanceof Method)) return false;
 173             MethodSymbol o = ((Method)any).other;
 174             MethodSymbol m = this.other;
 175             return
 176                 o.name == m.name &&
 177                 o.owner == m.owner &&
 178                 ((Method)any).uniqueType.equals(uniqueType);
 179         }
 180         @DefinedBy(Api.LANGUAGE_MODEL)
 181         public int hashCode() {
 182             MethodSymbol m = this.other;
 183             return
 184                 m.name.hashCode() * 33 +
 185                 m.owner.hashCode() * 9 +
 186                 uniqueType.hashCode();
 187         }
 188     }
 189 
 190     public static class DynamicMethod extends Method {
 191         public Object[] uniqueStaticArgs;
 192         Method internalBSM;
 193 
 194         public DynamicMethod(DynamicMethodSymbol m, Types types) {
 195             super(m, types);
 196             uniqueStaticArgs = getUniqueTypeArray(m.staticArgs, types);
 197             internalBSM = new Method(m.bsm, types);
 198         }
 199 
 200         @Override @DefinedBy(Api.LANGUAGE_MODEL)
 201         public boolean equals(Object any) {
 202             return equalsImpl(any, true);
 203         }
 204 
 205         protected boolean equalsImpl(Object any, boolean includeDynamicArgs) {
 206             if (includeDynamicArgs && !super.equals(any)) return false;
 207             if (!(any instanceof DynamicMethod)) return false;
 208             DynamicMethodSymbol dm1 = (DynamicMethodSymbol)other;
 209             DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)any).other;
 210             return internalBSM.equals(((DynamicMethod)any).internalBSM) &&
 211                         dm1.bsmKind == dm2.bsmKind &&
 212                         Arrays.equals(uniqueStaticArgs,
 213                             ((DynamicMethod)any).uniqueStaticArgs);
 214         }
 215 
 216         @Override @DefinedBy(Api.LANGUAGE_MODEL)
 217         public int hashCode() {
 218             return hashCodeImpl(true);
 219         }
 220 
 221         protected int hashCodeImpl(boolean includeDynamicArgs) {
 222             int hash = includeDynamicArgs ? super.hashCode() : 0;
 223             DynamicMethodSymbol dm = (DynamicMethodSymbol)other;
 224             hash += dm.bsmKind * 7 +
 225                     internalBSM.hashCode() * 11;
 226             for (int i = 0; i < dm.staticArgs.length; i++) {
 227                 hash += (uniqueStaticArgs[i].hashCode() * 23);
 228             }
 229             return hash;
 230         }
 231 
 232         private Object[] getUniqueTypeArray(Object[] objects, Types types) {
 233             Object[] result = new Object[objects.length];
 234             for (int i = 0; i < objects.length; i++) {
 235                 if (objects[i] instanceof Type) {
 236                     result[i] = new UniqueType((Type)objects[i], types);
 237                 } else {
 238                     result[i] = objects[i];
 239                 }
 240             }
 241             return result;
 242         }
 243 
 244         static class BootstrapMethodsKey extends DynamicMethod {
 245             BootstrapMethodsKey(DynamicMethodSymbol m, Types types) {
 246                 super(m, types);
 247             }
 248 
 249             @Override @DefinedBy(Api.LANGUAGE_MODEL)
 250             public boolean equals(Object any) {
 251                 return equalsImpl(any, false);
 252             }
 253 
 254             @Override @DefinedBy(Api.LANGUAGE_MODEL)
 255             public int hashCode() {
 256                 return hashCodeImpl(false);
 257             }
 258 
 259             Object[] getUniqueArgs() {
 260                 return uniqueStaticArgs;
 261             }
 262         }
 263 
 264         static class BootstrapMethodsValue {
 265             final MethodHandle mh;
 266             final int index;
 267 
 268             public BootstrapMethodsValue(MethodHandle mh, int index) {
 269                 this.mh = mh;
 270                 this.index = index;
 271             }
 272         }
 273     }
 274 
 275     static class Variable extends DelegatedSymbol<VarSymbol> {
 276         UniqueType uniqueType;
 277         Variable(VarSymbol v, Types types) {
 278             super(v);
 279             this.uniqueType = new UniqueType(v.type, types);
 280         }
 281         @DefinedBy(Api.LANGUAGE_MODEL)
 282         public boolean equals(Object any) {
 283             if (!(any instanceof Variable)) return false;
 284             VarSymbol o = ((Variable)any).other;
 285             VarSymbol v = other;
 286             return
 287                 o.name == v.name &&
 288                 o.owner == v.owner &&
 289                 ((Variable)any).uniqueType.equals(uniqueType);
 290         }
 291         @DefinedBy(Api.LANGUAGE_MODEL)
 292         public int hashCode() {
 293             VarSymbol v = other;
 294             return
 295                 v.name.hashCode() * 33 +
 296                 v.owner.hashCode() * 9 +
 297                 uniqueType.hashCode();
 298         }
 299     }
 300 
 301     /**
 302      * Pool entry associated with dynamic constants.
 303      */
 304     public static class DynamicVariable extends Variable {
 305         public MethodHandle bsm;
 306         private Object[] uniqueStaticArgs;
 307         Types types;
 308 
 309         public DynamicVariable(Name name, MethodHandle bsm, Object[] args, Types types, Symtab syms) {
 310             this(name, bsm, bsm.refSym.type.asMethodType().restype, args, types, syms);
 311         }
 312 
 313         public DynamicVariable(Name name, MethodHandle bsm, Type type, Object[] args, Types types, Symtab syms) {
 314             this(new DynamicVarSymbol(name,
 315                             syms.noSymbol,
 316                             bsm.refKind,
 317                             (MethodSymbol)bsm.refSym,
 318                             type,
 319                             args), types, bsm);
 320         }
 321 
 322         public DynamicVariable(DynamicVarSymbol dynField, Types types) {
 323             this(dynField, types, null);
 324         }
 325 
 326         private DynamicVariable(DynamicVarSymbol dynField, Types types, MethodHandle bsm) {
 327             super(dynField, types);
 328             this.bsm = bsm != null ?
 329                     bsm :
 330                     new MethodHandle(dynField.bsmKind, dynField.bsm, types);
 331             this.types = types;
 332             uniqueStaticArgs = getUniqueTypeArray(staticArgs(), types);
 333         }
 334 
 335         private Object[] getUniqueTypeArray(Object[] objects, Types types) {
 336             Object[] result = new Object[objects.length];
 337             for (int i = 0; i < objects.length; i++) {
 338                 if (objects[i] instanceof Type) {
 339                     result[i] = new UniqueType((Type)objects[i], types);
 340                 } else {
 341                     result[i] = objects[i];
 342                 }
 343             }
 344             return result;
 345         }
 346 
 347         @Override
 348         public int hashCode() {
 349             int hash = bsm.hashCode() * 67 + other.name.hashCode() + type.hashCode() * 13 + uniqueType.hashCode();
 350             for (Object uniqueStaticArg : uniqueStaticArgs) {
 351                 hash += (uniqueStaticArg.hashCode() * 23);
 352             }
 353             return hash;
 354         }
 355 
 356         @Override
 357         public boolean equals(Object obj) {
 358             if (obj instanceof DynamicVariable) {
 359                 DynamicVariable that = (DynamicVariable)obj;
 360                 return that.bsm.equals(bsm) &&
 361                         types.isSameType(that.type, type) &&
 362                         that.other.name.equals(other.name) &&
 363                         Arrays.equals(uniqueStaticArgs, that.uniqueStaticArgs) &&
 364                         that.uniqueType.equals(uniqueType);
 365             } else {
 366                 return false;
 367             }
 368         }
 369 
 370         public Object[] staticArgs() {
 371             return ((DynamicVarSymbol)other).staticArgs;
 372         }
 373     }
 374 
 375     public static class MethodHandle {
 376 
 377         /** Reference kind - see ClassFile */
 378         public int refKind;
 379 
 380         /** Reference symbol */
 381         public Symbol refSym;
 382 
 383         UniqueType uniqueType;
 384 
 385         public MethodHandle(int refKind, Symbol refSym, Types types) {
 386             this(refKind, refSym, types, new StrictMethodHandleCheckHelper(refKind, refSym));
 387         }
 388         public MethodHandle(int refKind, Symbol refSym, Types types, MethodHandleCheckHelper mhCheckHelper) {
 389             this.refKind = refKind;
 390             this.refSym = refSym;
 391             this.uniqueType = new UniqueType(this.refSym.type, types);
 392             mhCheckHelper.check();
 393         }
 394         public boolean equals(Object other) {
 395             if (!(other instanceof MethodHandle)) return false;
 396             MethodHandle mr = (MethodHandle) other;
 397             if (mr.refKind != refKind)  return false;
 398             Symbol o = mr.refSym;
 399             return
 400                 o.name == refSym.name &&
 401                 o.owner == refSym.owner &&
 402                 ((MethodHandle)other).uniqueType.equals(uniqueType);
 403         }
 404         public int hashCode() {
 405             return
 406                 refKind * 65 +
 407                 refSym.name.hashCode() * 33 +
 408                 refSym.owner.hashCode() * 9 +
 409                 uniqueType.hashCode();
 410         }
 411 
 412         public abstract static class MethodHandleCheckHelper {
 413             int refKind;
 414             Symbol refSym;
 415             public boolean staticOk = false;
 416             public Kind expectedKind = null;
 417             public Filter<Name> nameFilter = nonInitFilter;
 418             public boolean interfaceOwner = false;
 419 
 420             final static Filter<Name> nonInitFilter = n -> (n != n.table.names.init && n != n.table.names.clinit);
 421             final static Filter<Name> initFilter = n -> n == n.table.names.init;
 422 
 423             @SuppressWarnings("fallthrough")
 424             public MethodHandleCheckHelper(int refKind, Symbol refSym) {
 425                 this.refKind = refKind;
 426                 this.refSym = refSym;
 427                 switch (refKind) {
 428                     case ClassFile.REF_getStatic:
 429                     case ClassFile.REF_putStatic:
 430                         staticOk = true;
 431                     case ClassFile.REF_getField:
 432                     case ClassFile.REF_putField:
 433                         expectedKind = VAR;
 434                         break;
 435                     case ClassFile.REF_newInvokeSpecial:
 436                         nameFilter = initFilter;
 437                         expectedKind = MTH;
 438                         break;
 439                     case ClassFile.REF_invokeInterface:
 440                         interfaceOwner = true;
 441                         expectedKind = MTH;
 442                         break;
 443                     case ClassFile.REF_invokeStatic:
 444                         interfaceOwner = true;
 445                         staticOk = true;
 446                     case ClassFile.REF_invokeVirtual:
 447                         expectedKind = MTH;
 448                         break;
 449                     case ClassFile.REF_invokeSpecial:
 450                         interfaceOwner = true;
 451                         expectedKind = MTH;
 452                         break;
 453                 }
 454             }
 455 
 456             public abstract void check();
 457         }
 458 
 459         public static class DumbMethodHandleCheckHelper extends MethodHandleCheckHelper {
 460             public DumbMethodHandleCheckHelper(int refKind, Symbol refSym) {
 461                 super(refKind, refSym);
 462             }
 463 
 464             @Override
 465             public void check() {
 466                 // do nothing
 467             }
 468         }
 469 
 470         public static class StrictMethodHandleCheckHelper extends MethodHandleCheckHelper {
 471             public StrictMethodHandleCheckHelper(int refKind, Symbol refSym) {
 472                 super(refKind, refSym);
 473             }
 474 
 475             @Override
 476             public void check() {
 477                 Assert.check(!refSym.isStatic() || staticOk, "incorrect static-ness for symbol " + refSym);
 478                 Assert.check(refSym.kind == expectedKind, "unexpected kind for symbol " + refSym +". \n"
 479                         + "Expected = " + expectedKind + "\n"
 480                         + "Found = " + refSym.kind);
 481                 Assert.check(nameFilter.accepts(refSym.name), "incorrect name for symbol " + refSym);
 482                 boolean isInterface = (refSym.owner.flags_field & INTERFACE) != 0;
 483                 Assert.check(!isInterface || interfaceOwner,
 484                         interfaceOwner ?
 485                                 "interface owner expected for symbol ":
 486                                 "non interface owner expected for symbol " + refSym);
 487             }
 488         }
 489 
 490         public static class WarnMethodHandleCheckHelper extends MethodHandleCheckHelper {
 491             Log log;
 492             DiagnosticPosition pos;
 493             public WarnMethodHandleCheckHelper(Log log, DiagnosticPosition pos, int refKind, Symbol refSym) {
 494                 super(refKind, refSym);
 495                 this.log = log;
 496                 this.pos = pos;
 497             }
 498 
 499             @Override
 500             public void check() {
 501                 if (refSym.isStatic() != staticOk) {
 502                     log.warning(pos, Warnings.IncorrectStaticnessForSymbol(refSym));
 503                 }
 504                 if (refSym.kind != expectedKind) {
 505                     log.warning(pos, Warnings.UnexpectedKindForSymbol(refSym, expectedKind, refSym.kind));
 506                 }
 507                 if (!nameFilter.accepts(refSym.name)) {
 508                     log.warning(pos, Warnings.IncorrectNameForMethod(refSym, refKind));
 509                 }
 510                 boolean isInterface = (refSym.owner.flags_field & INTERFACE) != 0;
 511                 if (isInterface && !interfaceOwner) {
 512                     if (interfaceOwner) {
 513                         log.warning(pos, Warnings.InterfaceOwnerExpectedForSymbol(refSym));
 514                     } else {
 515                         log.warning(pos, Warnings.NonInterfaceOwnerExpectedForSymbol(refSym));
 516                     }
 517                 }
 518             }
 519         }
 520     }
 521 }