src/share/classes/com/sun/tools/javac/jvm/Pool.java

Fri, 30 Nov 2012 15:14:36 +0000

author
mcimadamore
date
Fri, 30 Nov 2012 15:14:36 +0000
changeset 1435
9b26c96f5138
parent 1415
01c9d4161882
child 1452
de1ec6fc93fe
permissions
-rw-r--r--

8004101: Add checks for method reference well-formedness
Summary: Bring method reference type-checking in sync with latest EDR
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 1999, 2012, 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  */
    26 package com.sun.tools.javac.jvm;
    28 import com.sun.tools.javac.code.Kinds;
    29 import com.sun.tools.javac.code.Symbol;
    30 import com.sun.tools.javac.code.Symbol.*;
    32 import com.sun.tools.javac.util.ArrayUtils;
    33 import com.sun.tools.javac.util.Assert;
    34 import com.sun.tools.javac.util.Filter;
    35 import com.sun.tools.javac.util.Name;
    37 import java.util.*;
    39 /** An internal structure that corresponds to the constant pool of a classfile.
    40  *
    41  *  <p><b>This is NOT part of any supported API.
    42  *  If you write code that depends on this, you do so at your own risk.
    43  *  This code and its internal interfaces are subject to change or
    44  *  deletion without notice.</b>
    45  */
    46 public class Pool {
    48     public static final int MAX_ENTRIES = 0xFFFF;
    49     public static final int MAX_STRING_LENGTH = 0xFFFF;
    51     /** Index of next constant to be entered.
    52      */
    53     int pp;
    55     /** The initial pool buffer.
    56      */
    57     Object[] pool;
    59     /** A hashtable containing all constants in the pool.
    60      */
    61     Map<Object,Integer> indices;
    63     /** Construct a pool with given number of elements and element array.
    64      */
    65     public Pool(int pp, Object[] pool) {
    66         this.pp = pp;
    67         this.pool = pool;
    68         this.indices = new HashMap<Object,Integer>(pool.length);
    69         for (int i = 1; i < pp; i++) {
    70             if (pool[i] != null) indices.put(pool[i], i);
    71         }
    72     }
    74     /** Construct an empty pool.
    75      */
    76     public Pool() {
    77         this(1, new Object[64]);
    78     }
    80     /** Return the number of entries in the constant pool.
    81      */
    82     public int numEntries() {
    83         return pp;
    84     }
    86     /** Remove everything from this pool.
    87      */
    88     public void reset() {
    89         pp = 1;
    90         indices.clear();
    91     }
    93     /** Place an object in the pool, unless it is already there.
    94      *  If object is a symbol also enter its owner unless the owner is a
    95      *  package.  Return the object's index in the pool.
    96      */
    97     public int put(Object value) {
    98         value = makePoolValue(value);
    99 //      assert !(value instanceof Type.TypeVar);
   100         Integer index = indices.get(value);
   101         if (index == null) {
   102 //          System.err.println("put " + value + " " + value.getClass());//DEBUG
   103             index = pp;
   104             indices.put(value, index);
   105             pool = ArrayUtils.ensureCapacity(pool, pp);
   106             pool[pp++] = value;
   107             if (value instanceof Long || value instanceof Double) {
   108                 pool = ArrayUtils.ensureCapacity(pool, pp);
   109                 pool[pp++] = null;
   110             }
   111         }
   112         return index.intValue();
   113     }
   115     Object makePoolValue(Object o) {
   116         if (o instanceof DynamicMethodSymbol) {
   117             return new DynamicMethod((DynamicMethodSymbol)o);
   118         } else if (o instanceof MethodSymbol) {
   119             return new Method((MethodSymbol)o);
   120         } else if (o instanceof VarSymbol) {
   121             return new Variable((VarSymbol)o);
   122         } else {
   123             return o;
   124         }
   125     }
   127     /** Return the given object's index in the pool,
   128      *  or -1 if object is not in there.
   129      */
   130     public int get(Object o) {
   131         Integer n = indices.get(o);
   132         return n == null ? -1 : n.intValue();
   133     }
   135     static class Method extends DelegatedSymbol {
   136         MethodSymbol m;
   137         Method(MethodSymbol m) {
   138             super(m);
   139             this.m = m;
   140         }
   141         public boolean equals(Object other) {
   142             if (!(other instanceof Method)) return false;
   143             MethodSymbol o = ((Method)other).m;
   144             return
   145                 o.name == m.name &&
   146                 o.owner == m.owner &&
   147                 o.type.equals(m.type);
   148         }
   149         public int hashCode() {
   150             return
   151                 m.name.hashCode() * 33 +
   152                 m.owner.hashCode() * 9 +
   153                 m.type.hashCode();
   154         }
   155     }
   157     static class DynamicMethod extends Method {
   159         DynamicMethod(DynamicMethodSymbol m) {
   160             super(m);
   161         }
   163         @Override
   164         public boolean equals(Object other) {
   165             if (!super.equals(other)) return false;
   166             if (!(other instanceof DynamicMethod)) return false;
   167             DynamicMethodSymbol dm1 = (DynamicMethodSymbol)m;
   168             DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)other).m;
   169             return dm1.bsm == dm2.bsm &&
   170                         dm1.bsmKind == dm2.bsmKind &&
   171                         Arrays.equals(dm1.staticArgs, dm2.staticArgs);
   172         }
   174         @Override
   175         public int hashCode() {
   176             int hash = super.hashCode();
   177             DynamicMethodSymbol dm = (DynamicMethodSymbol)m;
   178             hash += dm.bsmKind * 7 +
   179                     dm.bsm.hashCode() * 11;
   180             for (int i = 0; i < dm.staticArgs.length; i++) {
   181                 hash += (dm.staticArgs[i].hashCode() * 23);
   182             }
   183             return hash;
   184         }
   185     }
   187     static class Variable extends DelegatedSymbol {
   188         VarSymbol v;
   189         Variable(VarSymbol v) {
   190             super(v);
   191             this.v = v;
   192         }
   193         public boolean equals(Object other) {
   194             if (!(other instanceof Variable)) return false;
   195             VarSymbol o = ((Variable)other).v;
   196             return
   197                 o.name == v.name &&
   198                 o.owner == v.owner &&
   199                 o.type.equals(v.type);
   200         }
   201         public int hashCode() {
   202             return
   203                 v.name.hashCode() * 33 +
   204                 v.owner.hashCode() * 9 +
   205                 v.type.hashCode();
   206         }
   207     }
   209     public static class MethodHandle {
   211         /** Reference kind - see ClassFile */
   212         int refKind;
   214         /** Reference symbol */
   215         Symbol refSym;
   217         public MethodHandle(int refKind, Symbol refSym) {
   218             this.refKind = refKind;
   219             this.refSym = refSym;
   220             checkConsistent();
   221         }
   222         public boolean equals(Object other) {
   223             if (!(other instanceof MethodHandle)) return false;
   224             MethodHandle mr = (MethodHandle) other;
   225             if (mr.refKind != refKind)  return false;
   226             Symbol o = mr.refSym;
   227             return
   228                 o.name == refSym.name &&
   229                 o.owner == refSym.owner &&
   230                 o.type.equals(refSym.type);
   231         }
   232         public int hashCode() {
   233             return
   234                 refKind * 65 +
   235                 refSym.name.hashCode() * 33 +
   236                 refSym.owner.hashCode() * 9 +
   237                 refSym.type.hashCode();
   238         }
   240         /**
   241          * Check consistency of reference kind and symbol (see JVMS 4.4.8)
   242          */
   243         @SuppressWarnings("fallthrough")
   244         private void checkConsistent() {
   245             boolean staticOk = false;
   246             int expectedKind = -1;
   247             Filter<Name> nameFilter = nonInitFilter;
   248             boolean interfaceOwner = false;
   249             switch (refKind) {
   250                 case ClassFile.REF_getStatic:
   251                 case ClassFile.REF_putStatic:
   252                     staticOk = true;
   253                 case ClassFile.REF_getField:
   254                 case ClassFile.REF_putField:
   255                     expectedKind = Kinds.VAR;
   256                     break;
   257                 case ClassFile.REF_newInvokeSpecial:
   258                     nameFilter = initFilter;
   259                     expectedKind = Kinds.MTH;
   260                     break;
   261                 case ClassFile.REF_invokeInterface:
   262                     interfaceOwner = true;
   263                     expectedKind = Kinds.MTH;
   264                     break;
   265                 case ClassFile.REF_invokeStatic:
   266                     staticOk = true;
   267                 case ClassFile.REF_invokeVirtual:
   268                 case ClassFile.REF_invokeSpecial:
   269                     expectedKind = Kinds.MTH;
   270                     break;
   271             }
   272             Assert.check(!refSym.isStatic() || staticOk);
   273             Assert.check(refSym.kind == expectedKind);
   274             Assert.check(nameFilter.accepts(refSym.name));
   275             Assert.check(!refSym.owner.isInterface() || interfaceOwner);
   276         }
   277         //where
   278                 Filter<Name> nonInitFilter = new Filter<Name>() {
   279                     public boolean accepts(Name n) {
   280                         return n != n.table.names.init && n != n.table.names.clinit;
   281                     }
   282                 };
   284                 Filter<Name> initFilter = new Filter<Name>() {
   285                     public boolean accepts(Name n) {
   286                         return n == n.table.names.init;
   287                     }
   288                 };
   289     }
   290 }

mercurial