InternalNative.cpp revision 60fc806b679a3655c228b4093058c59941a49cfe
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* 18 * Internal-native initialization and some common utility functions. 19 */ 20#include "Dalvik.h" 21#include "native/InternalNativePriv.h" 22 23/* 24 * Set of classes for which we provide methods. 25 * 26 * The last field, classNameHash, is filled in at startup. 27 */ 28static DalvikNativeClass gDvmNativeMethodSet[] = { 29 { "Ljava/lang/Object;", dvm_java_lang_Object, 0 }, 30 { "Ljava/lang/Class;", dvm_java_lang_Class, 0 }, 31 { "Ljava/lang/Double;", dvm_java_lang_Double, 0 }, 32 { "Ljava/lang/Float;", dvm_java_lang_Float, 0 }, 33 { "Ljava/lang/Math;", dvm_java_lang_Math, 0 }, 34 { "Ljava/lang/Runtime;", dvm_java_lang_Runtime, 0 }, 35 { "Ljava/lang/String;", dvm_java_lang_String, 0 }, 36 { "Ljava/lang/System;", dvm_java_lang_System, 0 }, 37 { "Ljava/lang/Throwable;", dvm_java_lang_Throwable, 0 }, 38 { "Ljava/lang/VMClassLoader;", dvm_java_lang_VMClassLoader, 0 }, 39 { "Ljava/lang/VMThread;", dvm_java_lang_VMThread, 0 }, 40 { "Ljava/lang/reflect/AccessibleObject;", 41 dvm_java_lang_reflect_AccessibleObject, 0 }, 42 { "Ljava/lang/reflect/Array;", dvm_java_lang_reflect_Array, 0 }, 43 { "Ljava/lang/reflect/Constructor;", 44 dvm_java_lang_reflect_Constructor, 0 }, 45 { "Ljava/lang/reflect/Field;", dvm_java_lang_reflect_Field, 0 }, 46 { "Ljava/lang/reflect/Method;", dvm_java_lang_reflect_Method, 0 }, 47 { "Ljava/lang/reflect/Proxy;", dvm_java_lang_reflect_Proxy, 0 }, 48 { "Ljava/util/concurrent/atomic/AtomicLong;", 49 dvm_java_util_concurrent_atomic_AtomicLong, 0 }, 50 { "Ldalvik/bytecode/OpcodeInfo;", dvm_dalvik_bytecode_OpcodeInfo, 0 }, 51 { "Ldalvik/system/VMDebug;", dvm_dalvik_system_VMDebug, 0 }, 52 { "Ldalvik/system/DexFile;", dvm_dalvik_system_DexFile, 0 }, 53 { "Ldalvik/system/VMRuntime;", dvm_dalvik_system_VMRuntime, 0 }, 54 { "Ldalvik/system/Zygote;", dvm_dalvik_system_Zygote, 0 }, 55 { "Ldalvik/system/VMStack;", dvm_dalvik_system_VMStack, 0 }, 56 { "Lorg/apache/harmony/dalvik/ddmc/DdmServer;", 57 dvm_org_apache_harmony_dalvik_ddmc_DdmServer, 0 }, 58 { "Lorg/apache/harmony/dalvik/ddmc/DdmVmInternal;", 59 dvm_org_apache_harmony_dalvik_ddmc_DdmVmInternal, 0 }, 60 { "Lorg/apache/harmony/dalvik/NativeTestTarget;", 61 dvm_org_apache_harmony_dalvik_NativeTestTarget, 0 }, 62 { "Lsun/misc/Unsafe;", dvm_sun_misc_Unsafe, 0 }, 63 { NULL, NULL, 0 }, 64}; 65 66 67/* 68 * Set up hash values on the class names. 69 */ 70bool dvmInternalNativeStartup() 71{ 72 DalvikNativeClass* classPtr = gDvmNativeMethodSet; 73 74 while (classPtr->classDescriptor != NULL) { 75 classPtr->classDescriptorHash = 76 dvmComputeUtf8Hash(classPtr->classDescriptor); 77 classPtr++; 78 } 79 80 gDvm.userDexFiles = dvmHashTableCreate(2, dvmFreeDexOrJar); 81 if (gDvm.userDexFiles == NULL) 82 return false; 83 84 return true; 85} 86 87/* 88 * Clean up. 89 */ 90void dvmInternalNativeShutdown() 91{ 92 dvmHashTableFree(gDvm.userDexFiles); 93} 94 95/* 96 * Search the internal native set for a match. 97 */ 98DalvikNativeFunc dvmLookupInternalNativeMethod(const Method* method) 99{ 100 const char* classDescriptor = method->clazz->descriptor; 101 const DalvikNativeClass* pClass; 102 u4 hash; 103 104 hash = dvmComputeUtf8Hash(classDescriptor); 105 pClass = gDvmNativeMethodSet; 106 while (true) { 107 if (pClass->classDescriptor == NULL) 108 break; 109 if (pClass->classDescriptorHash == hash && 110 strcmp(pClass->classDescriptor, classDescriptor) == 0) 111 { 112 const DalvikNativeMethod* pMeth = pClass->methodInfo; 113 while (true) { 114 if (pMeth->name == NULL) 115 break; 116 117 if (dvmCompareNameDescriptorAndMethod(pMeth->name, 118 pMeth->signature, method) == 0) 119 { 120 /* match */ 121 //LOGV("+++ match on %s.%s %s at %p", 122 // className, methodName, methodSignature, pMeth->fnPtr); 123 return pMeth->fnPtr; 124 } 125 126 pMeth++; 127 } 128 } 129 130 pClass++; 131 } 132 133 return NULL; 134} 135 136 137/* 138 * Magic "internal native" code stub, inserted into abstract method 139 * definitions when a class is first loaded. This throws the expected 140 * exception so we don't have to explicitly check for it in the interpreter. 141 */ 142void dvmAbstractMethodStub(const u4* args, JValue* pResult) 143{ 144 LOGD("--- called into dvmAbstractMethodStub"); 145 dvmThrowAbstractMethodError("abstract method not implemented"); 146} 147 148 149/* 150 * Verify that "obj" is non-null and is an instance of "clazz". 151 * Used to implement reflection on fields and methods. 152 * 153 * Returns "false" and throws an exception if not. 154 */ 155bool dvmVerifyObjectInClass(Object* obj, ClassObject* clazz) 156{ 157 ClassObject* exceptionClass = NULL; 158 159 if (obj == NULL) { 160 exceptionClass = gDvm.exNullPointerException; 161 } else if (!dvmInstanceof(obj->clazz, clazz)) { 162 exceptionClass = gDvm.exIllegalArgumentException; 163 } 164 165 if (exceptionClass != NULL) { 166 char* expectedClassName = dvmHumanReadableDescriptor(clazz->descriptor); 167 char* actualClassName = (obj != NULL) 168 ? dvmHumanReadableDescriptor(obj->clazz->descriptor) 169 : strdup("null"); 170 dvmThrowExceptionFmt(exceptionClass, 171 "expected receiver of type %s, but got %s", 172 expectedClassName, actualClassName); 173 free(expectedClassName); 174 free(actualClassName); 175 return false; 176 } 177 return true; 178} 179 180/* 181 * Find a class by name, initializing it if requested. 182 */ 183ClassObject* dvmFindClassByName(StringObject* nameObj, Object* loader, 184 bool doInit) 185{ 186 ClassObject* clazz = NULL; 187 char* name = NULL; 188 char* descriptor = NULL; 189 190 if (nameObj == NULL) { 191 dvmThrowNullPointerException(NULL); 192 goto bail; 193 } 194 name = dvmCreateCstrFromString(nameObj); 195 196 /* 197 * We need to validate and convert the name (from x.y.z to x/y/z). This 198 * is especially handy for array types, since we want to avoid 199 * auto-generating bogus array classes. 200 */ 201 if (!dexIsValidClassName(name, true)) { 202 LOGW("dvmFindClassByName rejecting '%s'", name); 203 dvmThrowClassNotFoundException(name); 204 goto bail; 205 } 206 207 descriptor = dvmDotToDescriptor(name); 208 if (descriptor == NULL) { 209 goto bail; 210 } 211 212 if (doInit) 213 clazz = dvmFindClass(descriptor, loader); 214 else 215 clazz = dvmFindClassNoInit(descriptor, loader); 216 217 if (clazz == NULL) { 218 LOGVV("FAIL: load %s (%d)", descriptor, doInit); 219 Thread* self = dvmThreadSelf(); 220 Object* oldExcep = dvmGetException(self); 221 dvmAddTrackedAlloc(oldExcep, self); /* don't let this be GCed */ 222 dvmClearException(self); 223 dvmThrowChainedClassNotFoundException(name, oldExcep); 224 dvmReleaseTrackedAlloc(oldExcep, self); 225 } else { 226 LOGVV("GOOD: load %s (%d) --> %p ldr=%p", 227 descriptor, doInit, clazz, clazz->classLoader); 228 } 229 230bail: 231 free(name); 232 free(descriptor); 233 return clazz; 234} 235 236/* 237 * We insert native method stubs for abstract methods so we don't have to 238 * check the access flags at the time of the method call. This results in 239 * "native abstract" methods, which can't exist. If we see the "abstract" 240 * flag set, clear the "native" flag. 241 * 242 * We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED 243 * position, because the callers of this function are trying to convey 244 * the "traditional" meaning of the flags to their callers. 245 */ 246u4 dvmFixMethodFlags(u4 flags) 247{ 248 if ((flags & ACC_ABSTRACT) != 0) { 249 flags &= ~ACC_NATIVE; 250 } 251 252 flags &= ~ACC_SYNCHRONIZED; 253 254 if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) { 255 flags |= ACC_SYNCHRONIZED; 256 } 257 258 return flags & JAVA_FLAGS_MASK; 259} 260