summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/driver/compiler_driver.cc64
-rw-r--r--runtime/interpreter/interpreter_common.cc21
-rw-r--r--runtime/mirror/stack_trace_element.h9
-rw-r--r--runtime/mirror/throwable.cc55
-rw-r--r--runtime/mirror/throwable.h4
-rw-r--r--runtime/thread.cc7
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());