diff options
-rw-r--r-- | compiler/driver/compiler_driver.cc | 64 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_common.cc | 21 | ||||
-rw-r--r-- | runtime/mirror/stack_trace_element.h | 9 | ||||
-rw-r--r-- | runtime/mirror/throwable.cc | 55 | ||||
-rw-r--r-- | runtime/mirror/throwable.h | 4 | ||||
-rw-r--r-- | runtime/thread.cc | 7 |
6 files changed, 107 insertions, 53 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index bde0fae..e5decc5 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1700,44 +1700,34 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl !StringPiece(descriptor).ends_with("$NoPreloadHolder;"); if (can_init_static_fields) { VLOG(compiler) << "Initializing: " << descriptor; - if (strcmp("Ljava/lang/Void;", descriptor) == 0) { - // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime. - ObjectLock<mirror::Class> lock(soa.Self(), &klass); - mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields(); - CHECK_EQ(fields->GetLength(), 1); - fields->Get(0)->SetObj<false>(klass.get(), - manager->GetClassLinker()->FindPrimitiveClass('V')); - klass->SetStatus(mirror::Class::kStatusInitialized, soa.Self()); - } else { - // TODO multithreading support. We should ensure the current compilation thread has - // exclusive access to the runtime and the transaction. To achieve this, we could use - // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity - // checks in Thread::AssertThreadSuspensionIsAllowable. - Runtime* const runtime = Runtime::Current(); - Transaction transaction; - - // Run the class initializer in transaction mode. - runtime->EnterTransactionMode(&transaction); - const mirror::Class::Status old_status = klass->GetStatus(); - bool success = manager->GetClassLinker()->EnsureInitialized(klass, true, true); - // TODO we detach transaction from runtime to indicate we quit the transactional - // mode which prevents the GC from visiting objects modified during the transaction. - // Ensure GC is not run so don't access freed objects when aborting transaction. - const char* old_casue = soa.Self()->StartAssertNoThreadSuspension("Transaction end"); - runtime->ExitTransactionMode(); - - if (!success) { - CHECK(soa.Self()->IsExceptionPending()); - ThrowLocation throw_location; - mirror::Throwable* exception = soa.Self()->GetException(&throw_location); - VLOG(compiler) << "Initialization of " << descriptor << " aborted because of " - << exception->Dump(); - soa.Self()->ClearException(); - transaction.Abort(); - CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored"; - } - soa.Self()->EndAssertNoThreadSuspension(old_casue); + // TODO multithreading support. We should ensure the current compilation thread has + // exclusive access to the runtime and the transaction. To achieve this, we could use + // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity + // checks in Thread::AssertThreadSuspensionIsAllowable. + Runtime* const runtime = Runtime::Current(); + Transaction transaction; + + // Run the class initializer in transaction mode. + runtime->EnterTransactionMode(&transaction); + const mirror::Class::Status old_status = klass->GetStatus(); + bool success = manager->GetClassLinker()->EnsureInitialized(klass, true, true); + // TODO we detach transaction from runtime to indicate we quit the transactional + // mode which prevents the GC from visiting objects modified during the transaction. + // Ensure GC is not run so don't access freed objects when aborting transaction. + const char* old_casue = soa.Self()->StartAssertNoThreadSuspension("Transaction end"); + runtime->ExitTransactionMode(); + + if (!success) { + CHECK(soa.Self()->IsExceptionPending()); + ThrowLocation throw_location; + mirror::Throwable* exception = soa.Self()->GetException(&throw_location); + VLOG(compiler) << "Initialization of " << descriptor << " aborted because of " + << exception->Dump(); + soa.Self()->ClearException(); + transaction.Abort(); + CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored"; } + soa.Self()->EndAssertNoThreadSuspension(old_casue); } } soa.Self()->AssertNoPendingException(); diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index da3e8ea..ee6a869 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -302,6 +302,8 @@ static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh, CHECK(found != NULL) << "Class.forName failed in un-started runtime for class: " << PrettyDescriptor(descriptor); result->SetL(found); + } else if (name == "java.lang.Class java.lang.Void.lookupType()") { + result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V')); } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") { SirtRef<ClassLoader> class_loader(self, down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset))); std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset + 1)->AsString()->ToModifiedUtf8().c_str())); @@ -355,6 +357,12 @@ static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh, args[0] = StackReference<mirror::Object>::FromMirrorPtr(found).AsVRegValue(); EnterInterpreterFromInvoke(self, c, field.get(), args, NULL); result->SetL(field.get()); + } else if (name == "int java.lang.Object.hashCode()") { + Object* obj = shadow_frame->GetVRegReference(arg_offset); + result->SetI(obj->IdentityHashCode()); + } else if (name == "java.lang.String java.lang.reflect.ArtMethod.getMethodName(java.lang.reflect.ArtMethod)") { + ArtMethod* method = shadow_frame->GetVRegReference(arg_offset)->AsArtMethod(); + result->SetL(MethodHelper(method).GetNameAsString()); } else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)" || name == "void java.lang.System.arraycopy(char[], int, char[], int, int)") { // Special case array copying without initializing System. @@ -381,7 +389,18 @@ static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh, dst->Set(dstPos + i, src->Get(srcPos + i)); } } else { - UNIMPLEMENTED(FATAL) << "System.arraycopy of unexpected type: " << PrettyDescriptor(ctype); + self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(), "Ljava/lang/InternalError;", + "Unimplemented System.arraycopy for type '%s'", + PrettyDescriptor(ctype).c_str()); + } + } else if (name == "java.lang.Object java.lang.ThreadLocal.get()") { + std::string caller(PrettyMethod(shadow_frame->GetLink()->GetMethod())); + if (caller == "java.lang.String java.lang.IntegralToString.convertInt(java.lang.AbstractStringBuilder, int)") { + // Allocate non-threadlocal buffer. + result->SetL(mirror::CharArray::Alloc(self, 11)); + } else { + self->ThrowNewException(self->GetCurrentLocationForThrow(), "Ljava/lang/InternalError;", + "Unimplemented ThreadLocal.get"); } } else { // Not special, continue with regular interpreter execution. diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h index 1acbbb0..c324d96 100644 --- a/runtime/mirror/stack_trace_element.h +++ b/runtime/mirror/stack_trace_element.h @@ -57,6 +57,10 @@ class MANAGED StackTraceElement : public Object { static void ResetClass(); static void VisitRoots(RootCallback* callback, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static Class* GetStackTraceElement() { + DCHECK(java_lang_StackTraceElement_ != NULL); + return java_lang_StackTraceElement_; + } private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". @@ -70,11 +74,6 @@ class MANAGED StackTraceElement : public Object { SirtRef<String>& file_name, int32_t line_number) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - static Class* GetStackTraceElement() { - DCHECK(java_lang_StackTraceElement_ != NULL); - return java_lang_StackTraceElement_; - } - static Class* java_lang_StackTraceElement_; friend struct art::StackTraceElementOffsets; // for verifying offset information diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc index d393a13..6874fe5 100644 --- a/runtime/mirror/throwable.cc +++ b/runtime/mirror/throwable.cc @@ -24,6 +24,7 @@ #include "object_array.h" #include "object_array-inl.h" #include "object_utils.h" +#include "stack_trace_element.h" #include "utils.h" #include "well_known_classes.h" @@ -53,6 +54,15 @@ void Throwable::SetCause(Throwable* cause) { } } +void Throwable::SetStackState(Object* state) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + CHECK(state != nullptr); + if (Runtime::Current()->IsActiveTransaction()) { + SetFieldObjectVolatile<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), state); + } else { + SetFieldObjectVolatile<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), state); + } +} + bool Throwable::IsCheckedException() { if (InstanceOf(WellKnownClasses::ToClass(WellKnownClasses::java_lang_Error))) { return false; @@ -70,24 +80,49 @@ std::string Throwable::Dump() { result += "\n"; Object* stack_state = GetStackState(); // check stack state isn't missing or corrupt - if (stack_state != NULL && stack_state->IsObjectArray()) { + if (stack_state != nullptr && stack_state->IsObjectArray()) { // Decode the internal stack trace into the depth and method trace ObjectArray<Object>* method_trace = down_cast<ObjectArray<Object>*>(stack_state); int32_t depth = method_trace->GetLength() - 1; IntArray* pc_trace = down_cast<IntArray*>(method_trace->Get(depth)); MethodHelper mh; - for (int32_t i = 0; i < depth; ++i) { - ArtMethod* method = down_cast<ArtMethod*>(method_trace->Get(i)); - mh.ChangeMethod(method); - uint32_t dex_pc = pc_trace->Get(i); - int32_t line_number = mh.GetLineNumFromDexPC(dex_pc); - const char* source_file = mh.GetDeclaringClassSourceFile(); - result += StringPrintf(" at %s (%s:%d)\n", PrettyMethod(method, true).c_str(), - source_file, line_number); + if (depth == 0) { + result += "(Throwable with empty stack trace)"; + } else { + for (int32_t i = 0; i < depth; ++i) { + ArtMethod* method = down_cast<ArtMethod*>(method_trace->Get(i)); + mh.ChangeMethod(method); + uint32_t dex_pc = pc_trace->Get(i); + int32_t line_number = mh.GetLineNumFromDexPC(dex_pc); + const char* source_file = mh.GetDeclaringClassSourceFile(); + result += StringPrintf(" at %s (%s:%d)\n", PrettyMethod(method, true).c_str(), + source_file, line_number); + } + } + } else { + Object* stack_trace = GetStackTrace(); + if (stack_trace != nullptr && stack_trace->IsObjectArray()) { + CHECK_EQ(stack_trace->GetClass()->GetComponentType(), + StackTraceElement::GetStackTraceElement()); + ObjectArray<StackTraceElement>* ste_array = + down_cast<ObjectArray<StackTraceElement>*>(stack_trace); + if (ste_array->GetLength() == 0) { + result += "(Throwable with empty stack trace)"; + } else { + for (int32_t i = 0; i < ste_array->GetLength(); ++i) { + StackTraceElement* ste = ste_array->Get(i); + result += StringPrintf(" at %s (%s:%d)\n", + ste->GetMethodName()->ToModifiedUtf8().c_str(), + ste->GetFileName()->ToModifiedUtf8().c_str(), + ste->GetLineNumber()); + } + } + } else { + result += "(Throwable with no stack trace)"; } } Throwable* cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_)); - if (cause != NULL && cause != this) { // Constructor makes cause == this by default. + if (cause != nullptr && cause != this) { // Constructor makes cause == this by default. result += "Caused by: "; result += cause->Dump(); } diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h index 950b5e7..c4127e0 100644 --- a/runtime/mirror/throwable.h +++ b/runtime/mirror/throwable.h @@ -42,6 +42,7 @@ class MANAGED Throwable : public Object { // overridden. Also it asserts rather than throwing exceptions. Currently this is only used // in cases like the verifier where the checks cannot fail and initCause isn't overridden. void SetCause(Throwable* cause) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetStackState(Object* state) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool IsCheckedException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static Class* GetJavaLangThrowable() { @@ -58,6 +59,9 @@ class MANAGED Throwable : public Object { Object* GetStackState() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_)); } + Object* GetStackTrace() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_trace_)); + } // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". HeapReference<Throwable> cause_; diff --git a/runtime/thread.cc b/runtime/thread.cc index e67a64f..23a6779 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1639,6 +1639,13 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location, if (cause.get() != nullptr) { exception->SetCause(down_cast<mirror::Throwable*>(DecodeJObject(cause.get()))); } + ScopedLocalRef<jobject> trace(GetJniEnv(), + Runtime::Current()->IsActiveTransaction() + ? CreateInternalStackTrace<true>(soa) + : CreateInternalStackTrace<false>(soa)); + if (trace.get() != nullptr) { + exception->SetStackState(down_cast<mirror::Throwable*>(DecodeJObject(trace.get()))); + } ThrowLocation gc_safe_throw_location(saved_throw_this.get(), saved_throw_method.get(), throw_location.GetDexPc()); SetException(gc_safe_throw_location, exception.get()); |