2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
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
10 * http://www.apache.org/licenses/LICENSE-2.0.
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.
18 package gov.nasa.jpf.vm;
22 import gov.nasa.jpf.annotation.MJI;
23 import gov.nasa.jpf.vm.ClassPath;
24 import gov.nasa.jpf.vm.ClassInfo;
25 import gov.nasa.jpf.vm.ClassLoaderInfo;
26 import gov.nasa.jpf.vm.ClassInfoException;
27 import gov.nasa.jpf.vm.ClinitRequired;
28 import gov.nasa.jpf.vm.ElementInfo;
29 import gov.nasa.jpf.vm.Heap;
30 import gov.nasa.jpf.vm.MJIEnv;
31 import gov.nasa.jpf.vm.NativePeer;
32 import gov.nasa.jpf.vm.ThreadInfo;
35 * @author Nastaran Shafiei <nastaran.shafiei@gmail.com>
37 * Native peer for java.lang.ClassLoader
39 public class JPF_java_lang_ClassLoader extends NativePeer {
42 public void $init____V (MJIEnv env, int objRef) {
43 ClassLoaderInfo systemCl = ClassLoaderInfo.getCurrentSystemClassLoader();
44 $init__Ljava_lang_ClassLoader_2__V (env, objRef, systemCl.getClassLoaderObjectRef());
48 public void $init__Ljava_lang_ClassLoader_2__V (MJIEnv env, int objRef, int parentRef) {
49 Heap heap = env.getHeap();
51 //--- Retrieve the parent ClassLoaderInfo
52 ClassLoaderInfo parent = env.getClassLoaderInfo(parentRef);
54 //--- create the internal representation of the classloader
55 ClassLoaderInfo cl = new ClassLoaderInfo(env.getVM(), objRef, new ClassPath(), parent);
57 //--- initialize the java.lang.ClassLoader object
58 ElementInfo ei = heap.getModifiable(objRef);
59 ei.setIntField( ClassLoaderInfo.ID_FIELD, cl.getId());
61 // we should use the following block if we ever decide to make systemClassLoader
62 // unavailable if(parent.isSystemClassLoader) {
63 // // we don't want to make the systemCLassLoader available through SUT
64 // parentRef = MJIEnv.NULL;
67 ei.setReferenceField("parent", parentRef);
71 public int getSystemClassLoader____Ljava_lang_ClassLoader_2 (MJIEnv env, int clsObjRef) {
72 return ClassLoaderInfo.getCurrentSystemClassLoader().getClassLoaderObjectRef();
76 public int getResource0__Ljava_lang_String_2__Ljava_lang_String_2 (MJIEnv env, int objRef, int resRef){
77 String rname = env.getStringObject(resRef);
79 ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
81 String resourcePath = cl.findResource(rname);
83 return env.newString(resourcePath);
87 public int getResources0__Ljava_lang_String_2___3Ljava_lang_String_2 (MJIEnv env, int objRef, int resRef) {
88 String rname = env.getStringObject(resRef);
90 ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
92 String[] resources = cl.findResources(rname);
94 return env.newStringArray(resources);
98 public int findLoadedClass__Ljava_lang_String_2__Ljava_lang_Class_2 (MJIEnv env, int objRef, int nameRef) {
99 String cname = env.getStringObject(nameRef);
101 ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
103 ClassInfo ci = cl.getAlreadyResolvedClassInfo(cname);
105 return ci.getClassObjectRef();
112 public int findSystemClass__Ljava_lang_String_2__Ljava_lang_Class_2 (MJIEnv env, int objRef, int nameRef) {
113 String cname = env.getStringObject(nameRef);
115 ClassLoaderInfo cl = ClassLoaderInfo.getCurrentSystemClassLoader();
117 // TODO: Fix for Groovy's model-checking
118 // Get a clean class name and try to resolve
119 ClassInfo cir = cl.getAlreadyResolvedClassInfo(Types.getClassNameFromTypeName(cname));
121 checkForIllegalName(env, cname);
122 if(env.hasException()) {
127 ClassInfo ci = cl.getResolvedClassInfo(cname);
129 if(!ci.isRegistered()) {
130 ci.registerClass(env.getThreadInfo());
133 return ci.getClassObjectRef();
136 // TODO: Fix for Groovy's model-checking
137 // TODO: Load the SystemClassLoader if this ClassLoader fails, but just get it if it is already defined!
138 // TODO: This is needed for sun.reflect.GroovyMagic and some other classes
140 public int defineClass0__Ljava_lang_String_2_3BII__Ljava_lang_Class_2
141 (MJIEnv env, int objRef, int nameRef, int bufferRef, int offset, int length) {
142 String cname = env.getStringObject(nameRef);
143 ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
145 // determine whether that the corresponding class is already defined by this
146 // classloader, if so, this attempt is invalid, and loading throws a LinkageError
147 if (cl.getDefinedClassInfo(cname) != null) { // attempt to define twice
148 env.throwException("java.lang.LinkageError");
152 byte[] buffer = env.getByteArrayObject(bufferRef);
155 ClassInfo ci = cl.getResolvedClassInfo( cname, buffer, offset, length);
157 // Note: if the representation is not of a supported major or minor version, loading
158 // throws an UnsupportedClassVersionError. But for now, we do not check for this here
159 // since we don't do much with minor and major versions
161 ThreadInfo ti = env.getThreadInfo();
162 ci.registerClass(ti);
164 return ci.getClassObjectRef();
166 } catch (LoadOnJPFRequired rre) {
167 return searchThroughSystemClassLoader(env, objRef, nameRef, bufferRef, offset, length);
169 } catch (ClassInfoException cix){
170 if (cix.getExceptionClass().equals("java.lang.ClassNotFoundException")) {
171 return searchThroughSystemClassLoader(env, objRef, nameRef, bufferRef, offset, length);
173 env.throwException("java.lang.ClassFormatError");
179 private int searchThroughSystemClassLoader
180 (MJIEnv env, int objRef, int nameRef, int bufferRef, int offset, int length) {
182 int sysObjRef = env.getSystemClassLoaderInfo().getClassLoaderObjectRef();
183 if (objRef != sysObjRef) {
184 // Check if this class has been defined in the SystemClassLoader
185 ClassLoaderInfo cl = env.getSystemClassLoaderInfo();
186 String cname = env.getStringObject(nameRef);
187 if (cl.getDefinedClassInfo(cname) != null) {
188 ClassInfo ci = cl.getResolvedClassInfo(cname);
189 return ci.getClassObjectRef();
191 return defineClass0__Ljava_lang_String_2_3BII__Ljava_lang_Class_2
192 (env, sysObjRef, nameRef, bufferRef, offset, length);
195 env.throwException("java.lang.ClassNotFoundException");
200 protected static boolean check(MJIEnv env, String cname, byte[] buffer, int offset, int length) {
201 // throw SecurityExcpetion if the package prefix is java
202 checkForProhibitedPkg(env, cname);
204 // throw NoClassDefFoundError if the given class does name might
205 // not be a valid binary name
206 checkForIllegalName(env, cname);
208 // throw IndexOutOfBoundsException if buffer length is not consistent
210 checkData(env, buffer, offset, length);
212 return !env.hasException();
215 protected static void checkForProhibitedPkg(MJIEnv env, String name) {
216 if(name != null && name.startsWith("java.")) {
217 env.throwException("java.lang.SecurityException", "Prohibited package name: " + name);
221 protected static void checkForIllegalName(MJIEnv env, String name) {
222 if((name == null) || (name.length() == 0)) {
226 if((name.indexOf('/') != -1) || (name.charAt(0) == '[')) {
227 env.throwException("java.lang.NoClassDefFoundError", "IllegalName: " + name);
231 protected static void checkData(MJIEnv env, byte[] buffer, int offset, int length) {
232 if(offset<0 || length<0 || offset+length > buffer.length) {
233 env.throwException("java.lang.IndexOutOfBoundsException");
237 static String pkg_class_name = "java.lang.Package";
240 public int getPackages_____3Ljava_lang_Package_2 (MJIEnv env, int objRef) {
241 ClassLoaderInfo sysLoader = ClassLoaderInfo.getCurrentSystemClassLoader();
242 ClassInfo pkgClass = null;
244 pkgClass = sysLoader.getInitializedClassInfo(pkg_class_name, env.getThreadInfo());
245 } catch (ClinitRequired x){
246 env.handleClinitRequest(x.getRequiredClassInfo());
250 ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
251 // Returns all of the Packages defined by this class loader and its ancestors
252 Map<String, ClassLoaderInfo> pkgs = cl.getPackages();
253 int size = pkgs.size();
254 // create an array of type java.lang.Package
255 int pkgArr = env.newObjectArray(pkg_class_name, size);
258 for(String name: cl.getPackages().keySet()) {
259 int pkgRef = createPackageObject(env, pkgClass, name, cl);
260 // place the object into the array
261 env.setReferenceArrayElement(pkgArr, i++, pkgRef);
268 public int getPackage__Ljava_lang_String_2__Ljava_lang_Package_2 (MJIEnv env, int objRef, int nameRef) {
269 ClassLoaderInfo sysLoader = ClassLoaderInfo.getCurrentSystemClassLoader();
271 ClassInfo pkgClass = null;
273 pkgClass = sysLoader.getInitializedClassInfo(pkg_class_name, env.getThreadInfo());
274 } catch (ClinitRequired x){
275 env.handleClinitRequest(x.getRequiredClassInfo());
279 ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
280 String pkgName = env.getStringObject(nameRef);
281 if(cl.getPackages().get(pkgName)!=null) {
282 return createPackageObject(env, pkgClass, pkgName, cl);
288 public static int createPackageObject(MJIEnv env, ClassInfo pkgClass, String pkgName, ClassLoaderInfo cl) {
289 int pkgRef = env.newObject(pkgClass);
290 ElementInfo ei = env.getModifiableElementInfo(pkgRef);
292 ei.setReferenceField("pkgName", env.newString(pkgName));
293 ei.setReferenceField("loader", cl.getClassLoaderObjectRef());
294 // the rest of the fields set to some dummy value
295 ei.setReferenceField("specTitle", env.newString("spectitle"));
296 ei.setReferenceField("specVersion", env.newString("specversion"));
297 ei.setReferenceField("specVendor", env.newString("specvendor"));
298 ei.setReferenceField("implTitle", env.newString("impltitle"));
299 ei.setReferenceField("implVersion", env.newString("implversion"));
300 ei.setReferenceField("sealBase", MJIEnv.NULL);
306 public void setDefaultAssertionStatus__Z__V (MJIEnv env, int objRef, boolean enabled) {
307 ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
308 cl.setDefaultAssertionStatus(enabled);
312 public void setPackageAssertionStatus__Ljava_lang_String_2Z__V (MJIEnv env, int objRef, int strRef, boolean enabled) {
313 ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
314 String pkgName = env.getStringObject(strRef);
315 cl.setPackageAssertionStatus(pkgName, enabled);
319 public void setClassAssertionStatus__Ljava_lang_String_2Z__V (MJIEnv env, int objRef, int strRef, boolean enabled) {
320 ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
321 String clsName = env.getStringObject(strRef);
322 cl.setClassAssertionStatus(clsName, enabled);
326 public void clearAssertionStatus____V (MJIEnv env, int objRef) {
327 ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
328 cl.clearAssertionStatus();