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