30766815a6d94c857776e79673f43290a57c8608
[jpf-core.git] / src / main / gov / nasa / jpf / vm / SystemClassLoaderInfo.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18 package gov.nasa.jpf.vm;
19
20 import gov.nasa.jpf.Config;
21 import gov.nasa.jpf.JPF;
22 import gov.nasa.jpf.util.JPFLogger;
23
24 import java.io.File;
25 import java.util.ArrayList;
26 import java.util.List;
27
28 /**
29  * @author Nastaran Shafiei <nastaran.shafiei@gmail.com>
30  * 
31  * Represents the JPF system classloader which models the following hierarchy.
32  * 
33  *            ----------------
34  *            | Bootstrap CL |
35  *            ----------------
36  *                   |
37  *            ----------------
38  *            | Extension CL |
39  *            ----------------
40  *                   |
41  *           ------------------
42  *           | Application CL |
43  *           ------------------
44  *           
45  * Since in the standard VM user does not have any control over the built-in 
46  * classloaders hierarchy, in JPF, we model all three by an instance of 
47  * SystemClassLoader which is responsible to load classes from Java API, 
48  * standard extensions packages, and the local file system.     
49  */
50 public abstract class SystemClassLoaderInfo extends ClassLoaderInfo {
51
52   static JPFLogger log = JPF.getLogger("class");
53   
54   // we need to keep track of this in case something needs the current SystemClassLoaderInfo before we have a main thread
55   static SystemClassLoaderInfo lastInstance;  
56   
57   // note that initialization requires these to be startup classes
58   protected ClassInfo classLoaderClassInfo;
59   protected ClassInfo objectClassInfo;
60   protected ClassInfo classClassInfo;
61   protected ClassInfo stringClassInfo;
62   protected ClassInfo weakRefClassInfo;
63   protected ClassInfo refClassInfo;
64   protected ClassInfo enumClassInfo;
65   protected ClassInfo threadClassInfo;
66   protected ClassInfo threadGroupClassInfo;
67   protected ClassInfo charArrayClassInfo;
68
69   protected int unCachedClasses = 10;
70   
71   /**
72    * list of configurable Attributors for ClassInfos, MethodInfos and FieldInfos
73    * that are consulted after creating the ClassInfo but before notifying classLoaded() listeners
74    */
75   protected List<Attributor> attributors;
76   
77   
78   public SystemClassLoaderInfo (VM vm, int appId){
79      super(vm);
80
81      lastInstance = this;
82
83     // this is a hack - for user ClassLoaderInfos, we compute the id from the corresponding
84     // objRef of the JPF ClassLoader object. For SystemClassLoaderInfos we can't do that because
85     // they are created before we can create JPF objects. However, this is safe if we know
86     // the provided id is never going to be the objRef of a future ClassLoader object, which is
87     // a safe bet since the first objects created are all system Class objects that are never going to
88     // be recycled.
89     this.id = computeId(appId);
90     
91     initializeSystemClassPath( vm, appId);
92     initializeAttributors( vm, appId);
93   }
94   
95   protected abstract void initializeSystemClassPath (VM vm, int appId);
96   
97   protected void initializeAttributors (VM vm, int appId){
98     attributors = new ArrayList<Attributor>();
99     
100     Config conf = vm.getConfig();
101     String key = conf.getIndexableKey("vm.attributors", appId);
102     if (key != null){
103       for (Attributor a : conf.getInstances(key, Attributor.class)){
104         attributors.add(a);
105       }
106     }
107   }
108
109   public void addAttributor (Attributor a){
110     attributors.add(a);
111   }
112   
113   /**
114    * to be called on each ClassInfo created in the realm of this SystemClassLoader
115    */
116   @Override
117   protected void setAttributes (ClassInfo ci){
118     for (Attributor a: attributors){
119       a.setAttributes(ci);
120     }
121   }
122   
123   //--- these can be used to build the app specific system CP
124   protected File[] getPathElements (Config conf, String keyBase, int appId) {
125     File[] pathElements = null;
126
127     // try appId indexed key first
128     String key = keyBase + '.' + appId;
129     if (conf.containsKey(key)) {
130       pathElements = conf.getPathArray(key);
131
132     } else { // fall back to keyBase
133       pathElements = conf.getPathArray(keyBase);
134     }
135
136     return pathElements;
137   }
138   
139   @Override
140   public SystemClassLoaderInfo getSystemClassLoader() {
141     return this;
142   }
143
144   
145   @Override
146   public ClassInfo getResolvedClassInfo (String clsName){
147     ClassInfo ci = super.getResolvedClassInfo(clsName);
148     
149     if (unCachedClasses > 0){
150       updateCachedClassInfos(ci);
151     }
152     
153     return ci;
154   }
155
156   @Override
157   public boolean isSystemClassLoader() {
158     return true;
159   }
160
161   static boolean checkClassName (String clsName) {
162     if ( !clsName.matches("[a-zA-Z_$][a-zA-Z_$0-9.]*")) {
163       return false;
164     }
165
166     // well, those two could be part of valid class names, but
167     // in all likeliness somebody specified a filename instead of
168     // a classname
169     if (clsName.endsWith(".java")) {
170       return false;
171     }
172     if (clsName.endsWith(".class")) {
173       return false;
174     }
175
176     return true;
177   }
178   
179
180   @Override
181   public ClassInfo loadClass(String cname) {
182     return getResolvedClassInfo(cname);
183   }
184
185   @Override
186   protected ClassInfo loadSystemClass (String typeName){
187     System.out.println("Loading class: " + typeName);
188     return new ClassInfo( typeName, this);
189   }
190
191   protected void setClassLoaderObject (ElementInfo ei){
192     objRef = ei.getObjectRef();
193     //id = computeId(objRef);
194     
195     // cross link
196     ei.setIntField(ID_FIELD, id);
197   }
198   
199
200   //-- ClassInfos cache management --
201
202   protected void updateCachedClassInfos (ClassInfo ci) {
203     String name = ci.name;
204
205     if ((objectClassInfo == null) && name.equals("java.lang.Object")) {
206       objectClassInfo = ci; unCachedClasses--;
207     } else if ((classClassInfo == null) && name.equals("java.lang.Class")) {
208       classClassInfo = ci; unCachedClasses--;
209     } else if ((classLoaderClassInfo == null) && name.equals("java.lang.ClassLoader")) {
210       classInfo = ci;
211       classLoaderClassInfo = ci;  unCachedClasses--;
212     } else if ((stringClassInfo == null) && name.equals("java.lang.String")) {
213       stringClassInfo = ci; unCachedClasses--;
214     } else if ((charArrayClassInfo == null) && name.equals("[C")) {
215       charArrayClassInfo = ci; unCachedClasses--;
216     } else if ((weakRefClassInfo == null) && name.equals("java.lang.ref.WeakReference")) {
217       weakRefClassInfo = ci; unCachedClasses--;
218     } else if ((refClassInfo == null) && name.equals("java.lang.ref.Reference")) {
219       refClassInfo = ci; unCachedClasses--;
220     } else if ((enumClassInfo == null) && name.equals("java.lang.Enum")) {
221       enumClassInfo = ci; unCachedClasses--;
222     } else if ((threadClassInfo == null) && name.equals("java.lang.Thread")) {
223       threadClassInfo = ci; unCachedClasses--;
224     } else if ((threadGroupClassInfo == null) && name.equals("java.lang.ThreadGroup")) {
225       threadGroupClassInfo = ci; unCachedClasses--;
226     }
227   }
228   
229   protected ClassInfo getObjectClassInfo() {
230     return objectClassInfo;
231   }
232
233   protected ClassInfo getClassClassInfo() {
234     return classClassInfo;
235   }
236
237   protected ClassInfo getClassLoaderClassInfo() {
238     return classLoaderClassInfo;
239   }
240
241   protected ClassInfo getStringClassInfo() {
242     return stringClassInfo;
243   }
244   
245   protected ClassInfo getCharArrayClassInfo() {
246     return charArrayClassInfo;
247   }
248
249   protected ClassInfo getEnumClassInfo() {
250     return enumClassInfo;
251   }
252
253   protected ClassInfo getThreadClassInfo() {
254     return threadClassInfo;
255   }
256
257   protected ClassInfo getThreadGroupClassInfo() {
258     return threadGroupClassInfo;
259   }
260
261   protected ClassInfo getReferenceClassInfo() {
262     return refClassInfo;
263   }
264
265   protected ClassInfo getWeakReferenceClassInfo() {
266     return weakRefClassInfo;
267   }
268
269 }