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.compilers.opt; 014 015import org.jikesrvm.VM; 016import org.jikesrvm.classloader.RVMClass; 017import org.jikesrvm.classloader.RVMField; 018import org.jikesrvm.classloader.RVMMethod; 019import org.jikesrvm.classloader.TypeReference; 020import org.jikesrvm.util.ImmutableEntryHashMapRVM; 021 022/** 023 * database to hold field-level information 024 * this is a mapping from RVMField -> FieldDatabaseEntry 025 */ 026final class FieldDatabase { 027 private static final boolean DEBUG = false; 028 029 private final ImmutableEntryHashMapRVM<RVMField, FieldDatabase.FieldDatabaseEntry> db = 030 new ImmutableEntryHashMapRVM<RVMField, FieldDatabase.FieldDatabaseEntry>(); 031 032 FieldDatabaseEntry findOrCreateEntry(RVMField f) { 033 FieldDatabaseEntry e = db.get(f); 034 if (e == null) { 035 e = new FieldDatabaseEntry(f); 036 db.put(f, e); 037 } 038 return e; 039 } 040 041 /** 042 * @param f the field in question 043 * @return the concrete type of a field, or null if none determined 044 */ 045 public TypeReference getConcreteType(RVMField f) { 046 FieldDatabaseEntry e = db.get(f); 047 if (e == null) return null; 048 049 if (e.allMethodsAreAnalyzed()) { 050 return e.getConcreteType(); 051 } 052 053 return null; 054 } 055 056 /** 057 * A data structure holding information about a field. 058 */ 059 static final class FieldDatabaseEntry { 060 private final ImmutableEntryHashMapRVM<RVMMethod, FieldWriterInfo> summaries; 061 /** have we already determined all methods are analyzed? */ 062 boolean cachedAllAnalyzed; 063 /** cache a copy of the concrete type already determined for this field */ 064 TypeReference cachedConcreteType; 065 066 FieldWriterInfo findMethodInfo(RVMMethod m) { 067 return summaries.get(m); 068 } 069 070 // are all methods that may write this field analyzed already? 071 boolean allMethodsAreAnalyzed() { 072 073 if (cachedAllAnalyzed) return true; 074 for (FieldWriterInfo info : summaries.values()) { 075 if (!info.isAnalyzed()) return false; 076 } 077 cachedAllAnalyzed = true; 078 return true; 079 } 080 081 // return the concrete type of the field; null if no consistent 082 // concrete type has yet been determined. 083 TypeReference getConcreteType() { 084 if (cachedConcreteType != null) return cachedConcreteType; 085 TypeReference result = null; 086 for (FieldWriterInfo info : summaries.values()) { 087 if (!info.isAnalyzed()) return null; 088 if (info.isBottom()) return null; 089 TypeReference t = info.concreteType; 090 if (result != null) { 091 // make sure that all methods set the same concrete type. 092 if (result != t) return null; 093 } else { 094 result = info.concreteType; 095 } 096 } 097 // found a concrete type. cache it and return it. 098 cachedConcreteType = result; 099 return result; 100 } 101 102 // create a new FieldDatabaseEntry, with a FieldWriterInfo 103 // for each method that may write this field 104 FieldDatabaseEntry(RVMField f) { 105 if (VM.VerifyAssertions) VM._assert(f.isPrivate()); 106 107 RVMClass klass = f.getDeclaringClass(); 108 summaries = new ImmutableEntryHashMapRVM<RVMMethod, FieldWriterInfo>(1); 109 110 // walk thru each method of the declaring class. 111 // If a method m may write to f, then create a FieldWriterInfo for m 112 for (RVMMethod m : klass.getDeclaredMethods()) { 113 if (m.mayWrite(f)) { 114 FieldWriterInfo info = new FieldWriterInfo(); 115 if (DEBUG) debug("New summary METHOD " + m + " FIELD " + f + " INFO " + info); 116 summaries.put(m, info); 117 } 118 } 119 } 120 } // class FieldDatabaseEntry 121 122 /** 123 * A data structure holding information about a particular 124 * {@code <method,field>} combination, where the method 125 * may write the field. 126 */ 127 static final class FieldWriterInfo { 128 static final int BOTTOM = 0x1; 129 static final int ANALYZED = 0x2; 130 int status; 131 TypeReference concreteType; 132 133 void setBottom() { 134 status |= BOTTOM; 135 } 136 137 void setAnalyzed() { 138 status |= ANALYZED; 139 } 140 141 boolean isBottom() { 142 return (status & BOTTOM) != 0; 143 } 144 145 boolean isAnalyzed() { 146 return (status & ANALYZED) != 0; 147 } 148 } 149 150 // print a debug message 151 private static void debug(String s) { 152 if (DEBUG) VM.sysWrite(s + " \n"); 153 } 154}