| //===- 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 "mvm/VMKit.h" |
| |
| #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); |
| |
| mvm::Thread* mut = mvm::Thread::get(); |
| uint32 length = mut->getFrameContextLength(); |
| |
| Jnjvm* vm = JavaThread::j3Thread(mut)->getJVM(); |
| |
| if (sizeof(void*) == 4) { |
| ClassArray* cl = vm->upcalls->ArrayOfInt; |
| result = (ArrayPtr*) cl->doNew(length); |
| } else { |
| ClassArray* cl = vm->upcalls->ArrayOfLong; |
| result = (ArrayPtr*) cl->doNew(length); |
| } |
| |
| // Don't call th->getFrameContext because it is not GC-safe. |
| mvm::StackWalker Walker(mut); |
| 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->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 = meth->classDef->classLoader->vm; |
| 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<uintptr_t>(ip)); |
| |
| UserClass* newS = vm->upcalls->newStackTraceElement; |
| res = newS->doNew(); |
| vm->upcalls->initStackTraceElement->invokeIntSpecial(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(); |
| mvm::VMKit* vmkit = vm->vmkit; |
| 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 = vmkit->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 = vmkit->IPToMethodInfo(ArrayPtr::getElement((ArrayPtr*)stack, cur)); |
| ++cur; |
| if (MI->isHighLevelMethod()) ++size; |
| } |
| |
| result = (ArrayObject*) |
| vm->upcalls->stackTraceArray->doNew(size); |
| |
| cur = 0; |
| for (sint32 i = index; i < JavaArray::getSize(stack); ++i) { |
| mvm::MethodInfo* MI = vmkit->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; |
| } |
| |
| } |