//===- ClasspathVMClassLoader.cpp - GNU classpath java/lang/VMClassLoader -===// // // The VMKit project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "types.h" #include "Classpath.h" #include "JavaAccess.h" #include "JavaArray.h" #include "JavaClass.h" #include "JavaConstantPool.h" #include "JavaObject.h" #include "JavaString.h" #include "JavaThread.h" #include "JavaUpcalls.h" #include "Jnjvm.h" #include "Reader.h" using namespace j3; extern "C" { JavaObject* internalFillInStackTrace(JavaObject* throwable) { JavaObject* vmThrowable = 0; ArrayPtr* result = 0; llvm_gcroot(throwable, 0); llvm_gcroot(vmThrowable, 0); llvm_gcroot(result, 0); JavaThread* th = JavaThread::get(); Jnjvm* vm = th->getJVM(); uint32 length = th->getFrameContextLength(); if (sizeof(void*) == 4) { ClassArray* cl = vm->upcalls->ArrayOfInt; result = (ArrayPtr*) cl->doNew(length, vm); } else { ClassArray* cl = vm->upcalls->ArrayOfLong; result = (ArrayPtr*) cl->doNew(length, vm); } // Don't call th->getFrameContext because it is not GC-safe. mvm::StackWalker Walker(th); uint32_t i = 0; while (void* ip = *Walker) { ArrayPtr::setElement(result, ip, i); ++i; ++Walker; } // Set the tempory data in the new VMThrowable object. vmThrowable = vm->upcalls->newVMThrowable->doNew(vm); vm->upcalls->vmDataVMThrowable->setInstanceObjectField(vmThrowable, result); return vmThrowable; } JNIEXPORT JavaObject* JNICALL Java_java_lang_VMThrowable_fillInStackTrace( #ifdef NATIVE_JNI JNIEnv *env, jclass clazz, #endif JavaObject* throwable) { JavaObject* res = 0; llvm_gcroot(res, 0); llvm_gcroot(throwable, 0); BEGIN_NATIVE_EXCEPTION(0) res = internalFillInStackTrace(throwable); END_NATIVE_EXCEPTION return res; } JavaObject* consStackElement(JavaMethod* meth, void* ip) { JavaString* methodName = 0; JavaString* className = 0; JavaString* sourceName = 0; JavaObject* res = 0; llvm_gcroot(methodName, 0); llvm_gcroot(className, 0); llvm_gcroot(sourceName, 0); llvm_gcroot(res, 0); Jnjvm* vm = JavaThread::get()->getJVM(); methodName = vm->internalUTF8ToStr(meth->name); Class* cl = meth->classDef; className = JavaString::internalToJava(cl->name, vm); Attribut* sourceAtt = cl->lookupAttribut(Attribut::sourceFileAttribut); // We don't have the bytes if the class was vmjc'ed. if (sourceAtt && cl->getBytes()) { Reader reader(sourceAtt, cl->bytes); uint16 index = reader.readU2(); sourceName = vm->internalUTF8ToStr(cl->getConstantPool()->UTF8At(index)); } bool native = isNative(meth->access); uint16 lineNumber = meth->lookupLineNumber(reinterpret_cast(ip)); UserClass* newS = vm->upcalls->newStackTraceElement; res = newS->doNew(vm); vm->upcalls->initStackTraceElement->invokeIntSpecial(vm, newS, res, &sourceName, lineNumber, &className, &methodName, native); return res; } JNIEXPORT JavaObject* JNICALL Java_java_lang_VMThrowable_getStackTrace( #ifdef NATIVE_JNI JNIEnv *env, #endif JavaObject* vmthrow, JavaObject* throwable) { ArrayObject* result = NULL; JavaObject* stack = NULL; llvm_gcroot(vmthrow, 0); llvm_gcroot(throwable, 0); llvm_gcroot(result, 0); llvm_gcroot(stack, 0); BEGIN_NATIVE_EXCEPTION(0) Jnjvm* vm = JavaThread::get()->getJVM(); JavaField* field = vm->upcalls->vmDataVMThrowable; stack = field->getInstanceObjectField(vmthrow); // remove the VMThrowable.fillInStackTrace method and the last method // on the stack. sint32 index = 2;; while (index != JavaArray::getSize(stack)) { mvm::MethodInfo* MI = vm->IPToMethodInfo(ArrayPtr::getElement((ArrayPtr*)stack, index)); if (!MI->isHighLevelMethod()) ++index; else { JavaMethod* meth = (JavaMethod*)MI->MetaInfo; assert(meth && "Wrong stack trace"); if (meth->classDef->isAssignableFrom(vm->upcalls->newThrowable)) { ++index; } else break; } } sint32 size = 0; sint32 cur = index; while (cur < JavaArray::getSize(stack)) { mvm::MethodInfo* MI = vm->IPToMethodInfo(ArrayPtr::getElement((ArrayPtr*)stack, cur)); ++cur; if (MI->isHighLevelMethod()) ++size; } result = (ArrayObject*) vm->upcalls->stackTraceArray->doNew(size, vm); cur = 0; for (sint32 i = index; i < JavaArray::getSize(stack); ++i) { mvm::MethodInfo* MI = vm->IPToMethodInfo(ArrayPtr::getElement((ArrayPtr*)stack, i)); if (MI->isHighLevelMethod()) { JavaMethod* meth = (JavaMethod*)MI->MetaInfo; ArrayObject::setElement(result, consStackElement(meth, ArrayPtr::getElement((ArrayPtr*)stack, i)), cur); cur++; } } END_NATIVE_EXCEPTION return result; } }