001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.classloader;
014
015import java.util.WeakHashMap;
016
017/**
018 *  Lightweight implementation of a vector of Fields. This class is intended
019 *  to be used by a single thread and is therefore not thread-safe.
020 */
021final class MethodVector {
022  //-----------//
023  // interface //
024  //-----------//
025
026  MethodVector() {
027    array = new RVMMethod[10];
028  }
029
030  void addElement(RVMMethod item) {
031    if (cnt == array.length) {
032      adjustLength(cnt << 1); // double size of array
033    }
034    array[cnt++] = item;
035  }
036
037  /**
038   * Adds an item if it is not already in the vector. The test
039   * for the item uses object identity.
040   *
041   * @param item method to be added
042   */
043  public void addUniqueElement(RVMMethod item) {
044    for (int i = 0; i < cnt; i++) {
045      if (array[i] == item) return;
046    }
047    addElement(item);
048  }
049
050  RVMMethod elementAt(int index) {
051    return array[index];
052  }
053
054  void setElementAt(RVMMethod item, int index) {
055    array[index] = item;
056  }
057
058  public int size() {
059    return cnt;
060  }
061
062  /**
063   *
064   * @return an array of methods, trimmed to size. The returned array
065   *  is canonical: Adding the same set of methods in the same order
066   *  to different newly-created vectors {@code v1} and {@code v2}
067   *  will lead to the same array being returned for both {@code v1}
068   *  and {@code v2} when this method is called.
069   */
070  public RVMMethod[] finish() {
071    synchronized (MethodVector.class) {
072      RVMMethod[] result = popularMVs.get(this);
073      if (result != null) {
074        array = result;
075        return result;
076      } else {
077        adjustLength(cnt);
078        popularMVs.put(this, array);
079        return array;
080      }
081    }
082  }
083
084  @Override
085  public int hashCode() {
086    int val = 0;
087    for (int i = cnt - 1; i >= 0; i--) {
088      val ^= array[i].hashCode();
089    }
090    return val;
091  }
092
093  @Override
094  public boolean equals(Object obj) {
095    if (obj instanceof MethodVector) {
096      MethodVector that = (MethodVector)obj;
097      if (cnt != that.cnt) return false;
098      for (int i = cnt - 1; i >= 0; i--) {
099        if (array[i] != that.array[i]) return false;
100      }
101      return true;
102    } else {
103      return false;
104    }
105  }
106
107  //----------------//
108  // implementation //
109  //----------------//
110
111  private RVMMethod[] array;
112  private int cnt;
113
114  private static final RVMMethod[] empty = new RVMMethod[0];
115  private static final WeakHashMap<MethodVector, RVMMethod[]>
116    popularMVs = new WeakHashMap<MethodVector, RVMMethod[]>();
117
118  private void adjustLength(int newLength) {
119    if (newLength == 0) {
120      array = empty;
121    } else {
122      RVMMethod[] newElements = new RVMMethod[newLength];
123      int n = array.length;
124      if (n > newLength) {
125        n = newLength;
126      }
127
128      for (int i = 0; i < n; ++i) {
129        newElements[i] = array[i];
130      }
131
132      array = newElements;
133    }
134  }
135}