From 2969bcdcd80624e4a4fef696b54c2c76b44b6853 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Mon, 9 Mar 2015 12:57:41 -0700 Subject: [PATCH] ART: Refactor unstarted runtime Refactor and clean up unstarted runtime. Bug: 19542228 Change-Id: Ib3e4b3517e06e8242d4fed32ca59419fef553a47 --- dex2oat/dex2oat.cc | 7 + runtime/Android.mk | 1 + runtime/common_runtime_test.cc | 5 + runtime/interpreter/interpreter.cc | 109 +---- runtime/interpreter/interpreter_common.cc | 278 +---------- runtime/interpreter/interpreter_common.h | 7 - runtime/interpreter/unstarted_runtime.cc | 752 ++++++++++++++++++++++++++++++ runtime/interpreter/unstarted_runtime.h | 53 +++ runtime/transaction.cc | 2 +- 9 files changed, 823 insertions(+), 391 deletions(-) create mode 100644 runtime/interpreter/unstarted_runtime.cc create mode 100644 runtime/interpreter/unstarted_runtime.h diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index c3303e1f2..bb80a70e1 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -56,6 +56,7 @@ #include "gc/space/image_space.h" #include "gc/space/space-inl.h" #include "image_writer.h" +#include "interpreter/unstarted_runtime.h" #include "leb128.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" @@ -1541,8 +1542,14 @@ class Dex2Oat FINAL { } } runtime->GetClassLinker()->FixupDexCaches(runtime->GetResolutionMethod()); + + // Initialize maps for unstarted runtime. This needs to be here, as running clinits needs this + // set up. + interpreter::UnstartedRuntimeInitialize(); + runtime->GetClassLinker()->RunRootClinits(); runtime_ = runtime; + return true; } diff --git a/runtime/Android.mk b/runtime/Android.mk index af0c47976..8f203810e 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -80,6 +80,7 @@ LIBART_COMMON_SRC_FILES := \ interpreter/interpreter.cc \ interpreter/interpreter_common.cc \ interpreter/interpreter_switch_impl.cc \ + interpreter/unstarted_runtime.cc \ java_vm_ext.cc \ jdwp/jdwp_event.cc \ jdwp/jdwp_expand_buf.cc \ diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index 8dd9a4600..ceae9e857 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -236,6 +236,11 @@ void CommonRuntimeTest::SetUp() { runtime_.reset(Runtime::Current()); class_linker_ = runtime_->GetClassLinker(); class_linker_->FixupDexCaches(runtime_->GetResolutionMethod()); + + // Initialize maps for unstarted runtime. This needs to be here, as running clinits needs this + // set up. + interpreter::UnstartedRuntimeInitialize(); + class_linker_->RunRootClinits(); boot_class_path_ = class_linker_->GetBootClassPath(); java_lang_dex_file_ = boot_class_path_[0]; diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index 9d988e978..686b518c5 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -19,116 +19,13 @@ #include #include "mirror/string-inl.h" +#include "scoped_thread_state_change.h" +#include "ScopedLocalRef.h" +#include "unstarted_runtime.h" namespace art { namespace interpreter { -// Hand select a number of methods to be run in a not yet started runtime without using JNI. -static void UnstartedRuntimeJni(Thread* self, ArtMethod* method, - Object* receiver, uint32_t* args, JValue* result) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - std::string name(PrettyMethod(method)); - if (name == "java.lang.Object dalvik.system.VMRuntime.newUnpaddedArray(java.lang.Class, int)") { - int32_t length = args[1]; - DCHECK_GE(length, 0); - mirror::Class* element_class = reinterpret_cast(args[0])->AsClass(); - Runtime* runtime = Runtime::Current(); - mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(self, &element_class); - DCHECK(array_class != nullptr); - gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator(); - result->SetL(mirror::Array::Alloc(self, array_class, length, - array_class->GetComponentSizeShift(), allocator)); - } else if (name == "java.lang.ClassLoader dalvik.system.VMStack.getCallingClassLoader()") { - result->SetL(NULL); - } else if (name == "java.lang.Class dalvik.system.VMStack.getStackClass2()") { - NthCallerVisitor visitor(self, 3); - visitor.WalkStack(); - result->SetL(visitor.caller->GetDeclaringClass()); - } else if (name == "double java.lang.Math.log(double)") { - JValue value; - value.SetJ((static_cast(args[1]) << 32) | args[0]); - result->SetD(log(value.GetD())); - } else if (name == "java.lang.String java.lang.Class.getNameNative()") { - StackHandleScope<1> hs(self); - result->SetL(mirror::Class::ComputeName(hs.NewHandle(receiver->AsClass()))); - } else if (name == "int java.lang.Float.floatToRawIntBits(float)") { - result->SetI(args[0]); - } else if (name == "float java.lang.Float.intBitsToFloat(int)") { - result->SetI(args[0]); - } else if (name == "double java.lang.Math.exp(double)") { - JValue value; - value.SetJ((static_cast(args[1]) << 32) | args[0]); - result->SetD(exp(value.GetD())); - } else if (name == "java.lang.Object java.lang.Object.internalClone()") { - result->SetL(receiver->Clone(self)); - } else if (name == "void java.lang.Object.notifyAll()") { - receiver->NotifyAll(self); - } else if (name == "int java.lang.String.compareTo(java.lang.String)") { - String* rhs = reinterpret_cast(args[0])->AsString(); - CHECK(rhs != NULL); - result->SetI(receiver->AsString()->CompareTo(rhs)); - } else if (name == "java.lang.String java.lang.String.intern()") { - result->SetL(receiver->AsString()->Intern()); - } else if (name == "int java.lang.String.fastIndexOf(int, int)") { - result->SetI(receiver->AsString()->FastIndexOf(args[0], args[1])); - } else if (name == "java.lang.Object java.lang.reflect.Array.createMultiArray(java.lang.Class, int[])") { - StackHandleScope<2> hs(self); - auto h_class(hs.NewHandle(reinterpret_cast(args[0])->AsClass())); - auto h_dimensions(hs.NewHandle(reinterpret_cast(args[1])->AsIntArray())); - result->SetL(Array::CreateMultiArray(self, h_class, h_dimensions)); - } else if (name == "java.lang.Object java.lang.Throwable.nativeFillInStackTrace()") { - ScopedObjectAccessUnchecked soa(self); - if (Runtime::Current()->IsActiveTransaction()) { - result->SetL(soa.Decode(self->CreateInternalStackTrace(soa))); - } else { - result->SetL(soa.Decode(self->CreateInternalStackTrace(soa))); - } - } else if (name == "int java.lang.System.identityHashCode(java.lang.Object)") { - mirror::Object* obj = reinterpret_cast(args[0]); - result->SetI((obj != nullptr) ? obj->IdentityHashCode() : 0); - } else if (name == "boolean java.nio.ByteOrder.isLittleEndian()") { - result->SetZ(JNI_TRUE); - } else if (name == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") { - Object* obj = reinterpret_cast(args[0]); - jlong offset = (static_cast(args[2]) << 32) | args[1]; - jint expectedValue = args[3]; - jint newValue = args[4]; - bool success; - if (Runtime::Current()->IsActiveTransaction()) { - success = obj->CasFieldStrongSequentiallyConsistent32(MemberOffset(offset), - expectedValue, newValue); - } else { - success = obj->CasFieldStrongSequentiallyConsistent32(MemberOffset(offset), - expectedValue, newValue); - } - result->SetZ(success ? JNI_TRUE : JNI_FALSE); - } else if (name == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") { - Object* obj = reinterpret_cast(args[0]); - jlong offset = (static_cast(args[2]) << 32) | args[1]; - Object* newValue = reinterpret_cast(args[3]); - if (Runtime::Current()->IsActiveTransaction()) { - obj->SetFieldObject(MemberOffset(offset), newValue); - } else { - obj->SetFieldObject(MemberOffset(offset), newValue); - } - } else if (name == "int sun.misc.Unsafe.getArrayBaseOffsetForComponentType(java.lang.Class)") { - mirror::Class* component = reinterpret_cast(args[0])->AsClass(); - Primitive::Type primitive_type = component->GetPrimitiveType(); - result->SetI(mirror::Array::DataOffset(Primitive::ComponentSize(primitive_type)).Int32Value()); - } else if (name == "int sun.misc.Unsafe.getArrayIndexScaleForComponentType(java.lang.Class)") { - mirror::Class* component = reinterpret_cast(args[0])->AsClass(); - Primitive::Type primitive_type = component->GetPrimitiveType(); - result->SetI(Primitive::ComponentSize(primitive_type)); - } else if (Runtime::Current()->IsActiveTransaction()) { - AbortTransaction(self, "Attempt to invoke native method in non-started runtime: %s", - name.c_str()); - - } else { - LOG(FATAL) << "Calling native method " << PrettyMethod(method) << " in an unstarted " - "non-transactional runtime"; - } -} - static void InterpreterJni(Thread* self, ArtMethod* method, const StringPiece& shorty, Object* receiver, uint32_t* args, JValue* result) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 2a9c0d4c9..26ab602dc 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -19,6 +19,7 @@ #include #include "mirror/array-inl.h" +#include "unstarted_runtime.h" namespace art { namespace interpreter { @@ -450,10 +451,6 @@ void UnexpectedOpcode(const Instruction* inst, const ShadowFrame& shadow_frame) UNREACHABLE(); } -static void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item, - ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Assign register 'src_reg' from shadow_frame to register 'dest_reg' into new_shadow_frame. static inline void AssignRegister(ShadowFrame* new_shadow_frame, const ShadowFrame& shadow_frame, size_t dest_reg, size_t src_reg) @@ -733,279 +730,6 @@ void RecordArrayElementsInTransaction(mirror::Array* array, int32_t count) } } -// Helper function to deal with class loading in an unstarted runtime. -static void UnstartedRuntimeFindClass(Thread* self, Handle className, - Handle class_loader, JValue* result, - const std::string& method_name, bool initialize_class, - bool abort_if_not_found) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(className.Get() != nullptr); - std::string descriptor(DotToDescriptor(className->ToModifiedUtf8().c_str())); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - - Class* found = class_linker->FindClass(self, descriptor.c_str(), class_loader); - if (found == nullptr && abort_if_not_found) { - if (!self->IsExceptionPending()) { - AbortTransaction(self, "%s failed in un-started runtime for class: %s", - method_name.c_str(), PrettyDescriptor(descriptor.c_str()).c_str()); - } - return; - } - if (found != nullptr && initialize_class) { - StackHandleScope<1> hs(self); - Handle h_class(hs.NewHandle(found)); - if (!class_linker->EnsureInitialized(self, h_class, true, true)) { - CHECK(self->IsExceptionPending()); - return; - } - } - result->SetL(found); -} - -// Common helper for class-loading cutouts in an unstarted runtime. We call Runtime methods that -// rely on Java code to wrap errors in the correct exception class (i.e., NoClassDefFoundError into -// ClassNotFoundException), so need to do the same. The only exception is if the exception is -// actually InternalError. This must not be wrapped, as it signals an initialization abort. -static void CheckExceptionGenerateClassNotFound(Thread* self) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (self->IsExceptionPending()) { - // If it is not an InternalError, wrap it. - std::string type(PrettyTypeOf(self->GetException())); - if (type != "java.lang.InternalError") { - self->ThrowNewWrappedException("Ljava/lang/ClassNotFoundException;", - "ClassNotFoundException"); - } - } -} - -static void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item, - ShadowFrame* shadow_frame, - JValue* result, size_t arg_offset) { - // In a runtime that's not started we intercept certain methods to avoid complicated dependency - // problems in core libraries. - std::string name(PrettyMethod(shadow_frame->GetMethod())); - if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") { - mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString(); - StackHandleScope<1> hs(self); - Handle h_class_name(hs.NewHandle(class_name)); - UnstartedRuntimeFindClass(self, h_class_name, NullHandle(), result, name, - true, false); - CheckExceptionGenerateClassNotFound(self); - } else if (name == "java.lang.Class java.lang.Class.forName(java.lang.String, boolean, java.lang.ClassLoader)") { - mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString(); - bool initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0; - mirror::ClassLoader* class_loader = - down_cast(shadow_frame->GetVRegReference(arg_offset + 2)); - StackHandleScope<2> hs(self); - Handle h_class_name(hs.NewHandle(class_name)); - Handle h_class_loader(hs.NewHandle(class_loader)); - UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, name, initialize_class, - false); - CheckExceptionGenerateClassNotFound(self); - } else if (name == "java.lang.Class java.lang.Class.classForName(java.lang.String, boolean, java.lang.ClassLoader)") { - mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString(); - bool initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0; - mirror::ClassLoader* class_loader = - down_cast(shadow_frame->GetVRegReference(arg_offset + 2)); - StackHandleScope<2> hs(self); - Handle h_class_name(hs.NewHandle(class_name)); - Handle h_class_loader(hs.NewHandle(class_loader)); - UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, name, initialize_class, - false); - CheckExceptionGenerateClassNotFound(self); - } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") { - mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString(); - mirror::ClassLoader* class_loader = - down_cast(shadow_frame->GetVRegReference(arg_offset)); - StackHandleScope<2> hs(self); - Handle h_class_name(hs.NewHandle(class_name)); - Handle h_class_loader(hs.NewHandle(class_loader)); - UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, name, false, false); - // This might have an error pending. But semantics are to just return null. - if (self->IsExceptionPending()) { - // If it is an InternalError, keep it. See CheckExceptionGenerateClassNotFound. - std::string type(PrettyTypeOf(self->GetException())); - if (type != "java.lang.InternalError") { - self->ClearException(); - } - } - } else if (name == "java.lang.Class java.lang.Void.lookupType()") { - result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V')); - } else if (name == "java.lang.Object java.lang.Class.newInstance()") { - StackHandleScope<3> hs(self); // Class, constructor, object. - Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass(); - Handle h_klass(hs.NewHandle(klass)); - // There are two situations in which we'll abort this run. - // 1) If the class isn't yet initialized and initialization fails. - // 2) If we can't find the default constructor. We'll postpone the exception to runtime. - // Note that 2) could likely be handled here, but for safety abort the transaction. - bool ok = false; - if (Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_klass, true, true)) { - Handle h_cons(hs.NewHandle(h_klass->FindDeclaredDirectMethod("", "()V"))); - if (h_cons.Get() != nullptr) { - Handle h_obj(hs.NewHandle(klass->AllocObject(self))); - CHECK(h_obj.Get() != nullptr); // We don't expect OOM at compile-time. - EnterInterpreterFromInvoke(self, h_cons.Get(), h_obj.Get(), nullptr, nullptr); - if (!self->IsExceptionPending()) { - result->SetL(h_obj.Get()); - ok = true; - } - } else { - self->ThrowNewExceptionF("Ljava/lang/InternalError;", - "Could not find default constructor for '%s'", - PrettyClass(h_klass.Get()).c_str()); - } - } - if (!ok) { - std::string error_msg = StringPrintf("Failed in Class.newInstance for '%s' with %s", - PrettyClass(h_klass.Get()).c_str(), - PrettyTypeOf(self->GetException()).c_str()); - self->ThrowNewWrappedException("Ljava/lang/InternalError;", error_msg.c_str()); - } - } else if (name == "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") { - // Special managed code cut-out to allow field lookup in a un-started runtime that'd fail - // going the reflective Dex way. - Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass(); - String* name2 = shadow_frame->GetVRegReference(arg_offset + 1)->AsString(); - ArtField* found = NULL; - ObjectArray* fields = klass->GetIFields(); - for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) { - ArtField* f = fields->Get(i); - if (name2->Equals(f->GetName())) { - found = f; - } - } - if (found == NULL) { - fields = klass->GetSFields(); - for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) { - ArtField* f = fields->Get(i); - if (name2->Equals(f->GetName())) { - found = f; - } - } - } - CHECK(found != NULL) - << "Failed to find field in Class.getDeclaredField in un-started runtime. name=" - << name2->ToModifiedUtf8() << " class=" << PrettyDescriptor(klass); - // TODO: getDeclaredField calls GetType once the field is found to ensure a - // NoClassDefFoundError is thrown if the field's type cannot be resolved. - Class* jlr_Field = self->DecodeJObject(WellKnownClasses::java_lang_reflect_Field)->AsClass(); - StackHandleScope<1> hs(self); - Handle field(hs.NewHandle(jlr_Field->AllocNonMovableObject(self))); - CHECK(field.Get() != NULL); - ArtMethod* c = jlr_Field->FindDeclaredDirectMethod("", "(Ljava/lang/reflect/ArtField;)V"); - uint32_t args[1]; - args[0] = StackReference::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)") { - mirror::ArtMethod* method = shadow_frame->GetVRegReference(arg_offset)->AsArtMethod(); - result->SetL(method->GetNameAsString(self)); - } 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)" || - name == "void java.lang.System.arraycopy(int[], int, int[], int, int)") { - // Special case array copying without initializing System. - Class* ctype = shadow_frame->GetVRegReference(arg_offset)->GetClass()->GetComponentType(); - jint srcPos = shadow_frame->GetVReg(arg_offset + 1); - jint dstPos = shadow_frame->GetVReg(arg_offset + 3); - jint length = shadow_frame->GetVReg(arg_offset + 4); - if (!ctype->IsPrimitive()) { - ObjectArray* src = shadow_frame->GetVRegReference(arg_offset)->AsObjectArray(); - ObjectArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsObjectArray(); - for (jint i = 0; i < length; ++i) { - dst->Set(dstPos + i, src->Get(srcPos + i)); - } - } else if (ctype->IsPrimitiveChar()) { - CharArray* src = shadow_frame->GetVRegReference(arg_offset)->AsCharArray(); - CharArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsCharArray(); - for (jint i = 0; i < length; ++i) { - dst->Set(dstPos + i, src->Get(srcPos + i)); - } - } else if (ctype->IsPrimitiveInt()) { - IntArray* src = shadow_frame->GetVRegReference(arg_offset)->AsIntArray(); - IntArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsIntArray(); - for (jint i = 0; i < length; ++i) { - dst->Set(dstPos + i, src->Get(srcPos + i)); - } - } else { - self->ThrowNewExceptionF("Ljava/lang/InternalError;", - "Unimplemented System.arraycopy for type '%s'", - PrettyDescriptor(ctype).c_str()); - } - } else if (name == "long java.lang.Double.doubleToRawLongBits(double)") { - double in = shadow_frame->GetVRegDouble(arg_offset); - result->SetJ(bit_cast(in)); - } else if (name == "double java.lang.Math.ceil(double)") { - double in = shadow_frame->GetVRegDouble(arg_offset); - double out; - // Special cases: - // 1) NaN, infinity, +0, -0 -> out := in. All are guaranteed by cmath. - // -1 < in < 0 -> out := -0. - if (-1.0 < in && in < 0) { - out = -0.0; - } else { - out = ceil(in); - } - result->SetD(out); - } else if (name == "java.lang.Object java.lang.ThreadLocal.get()") { - std::string caller(PrettyMethod(shadow_frame->GetLink()->GetMethod())); - bool ok = false; - if (caller == "java.lang.String java.lang.IntegralToString.convertInt(java.lang.AbstractStringBuilder, int)") { - // Allocate non-threadlocal buffer. - result->SetL(mirror::CharArray::Alloc(self, 11)); - ok = true; - } else if (caller == "java.lang.RealToString java.lang.RealToString.getInstance()") { - // Note: RealToString is implemented and used in a different fashion than IntegralToString. - // Conversion is done over an actual object of RealToString (the conversion method is an - // instance method). This means it is not as clear whether it is correct to return a new - // object each time. The caller needs to be inspected by hand to see whether it (incorrectly) - // stores the object for later use. - // See also b/19548084 for a possible rewrite and bringing it in line with IntegralToString. - if (shadow_frame->GetLink()->GetLink() != nullptr) { - std::string caller2(PrettyMethod(shadow_frame->GetLink()->GetLink()->GetMethod())); - if (caller2 == "java.lang.String java.lang.Double.toString(double)") { - // Allocate new object. - StackHandleScope<2> hs(self); - Handle h_real_to_string_class(hs.NewHandle( - shadow_frame->GetLink()->GetMethod()->GetDeclaringClass())); - Handle h_real_to_string_obj(hs.NewHandle( - h_real_to_string_class->AllocObject(self))); - if (h_real_to_string_obj.Get() != nullptr) { - mirror::ArtMethod* init_method = - h_real_to_string_class->FindDirectMethod("", "()V"); - if (init_method == nullptr) { - h_real_to_string_class->DumpClass(LOG(FATAL), mirror::Class::kDumpClassFullDetail); - } else { - JValue invoke_result; - EnterInterpreterFromInvoke(self, init_method, h_real_to_string_obj.Get(), nullptr, - nullptr); - if (!self->IsExceptionPending()) { - result->SetL(h_real_to_string_obj.Get()); - ok = true; - } - } - } - - if (!ok) { - // We'll abort, so clear exception. - self->ClearException(); - } - } - } - } - - if (!ok) { - self->ThrowNewException("Ljava/lang/InternalError;", "Unimplemented ThreadLocal.get"); - } - } else { - // Not special, continue with regular interpreter execution. - artInterpreterToInterpreterBridge(self, code_item, shadow_frame, result); - } -} - // Explicit DoCall template function declarations. #define EXPLICIT_DO_CALL_TEMPLATE_DECL(_is_range, _do_assignability_check) \ template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) \ diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 3095316d8..15396d6e9 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -30,21 +30,14 @@ #include "common_throws.h" #include "dex_file-inl.h" #include "dex_instruction-inl.h" -#include "dex_instruction.h" #include "entrypoints/entrypoint_utils-inl.h" -#include "gc/accounting/card_table-inl.h" #include "handle_scope-inl.h" -#include "nth_caller_visitor.h" #include "mirror/art_field-inl.h" -#include "mirror/art_method.h" #include "mirror/art_method-inl.h" -#include "mirror/class.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/string-inl.h" -#include "ScopedLocalRef.h" -#include "scoped_thread_state_change.h" #include "thread.h" #include "well_known_classes.h" diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc new file mode 100644 index 000000000..99ce1e2f4 --- /dev/null +++ b/runtime/interpreter/unstarted_runtime.cc @@ -0,0 +1,752 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unstarted_runtime.h" + +#include +#include + +#include "base/logging.h" +#include "base/macros.h" +#include "class_linker.h" +#include "common_throws.h" +#include "entrypoints/entrypoint_utils-inl.h" +#include "handle_scope-inl.h" +#include "interpreter/interpreter_common.h" +#include "mirror/array-inl.h" +#include "mirror/art_method-inl.h" +#include "mirror/class.h" +#include "mirror/object-inl.h" +#include "mirror/object_array-inl.h" +#include "mirror/string-inl.h" +#include "nth_caller_visitor.h" +#include "thread.h" +#include "well_known_classes.h" + +namespace art { +namespace interpreter { + +// Helper function to deal with class loading in an unstarted runtime. +static void UnstartedRuntimeFindClass(Thread* self, Handle className, + Handle class_loader, JValue* result, + const std::string& method_name, bool initialize_class, + bool abort_if_not_found) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + CHECK(className.Get() != nullptr); + std::string descriptor(DotToDescriptor(className->ToModifiedUtf8().c_str())); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + + mirror::Class* found = class_linker->FindClass(self, descriptor.c_str(), class_loader); + if (found == nullptr && abort_if_not_found) { + if (!self->IsExceptionPending()) { + AbortTransaction(self, "%s failed in un-started runtime for class: %s", + method_name.c_str(), PrettyDescriptor(descriptor.c_str()).c_str()); + } + return; + } + if (found != nullptr && initialize_class) { + StackHandleScope<1> hs(self); + Handle h_class(hs.NewHandle(found)); + if (!class_linker->EnsureInitialized(self, h_class, true, true)) { + CHECK(self->IsExceptionPending()); + return; + } + } + result->SetL(found); +} + +// Common helper for class-loading cutouts in an unstarted runtime. We call Runtime methods that +// rely on Java code to wrap errors in the correct exception class (i.e., NoClassDefFoundError into +// ClassNotFoundException), so need to do the same. The only exception is if the exception is +// actually InternalError. This must not be wrapped, as it signals an initialization abort. +static void CheckExceptionGenerateClassNotFound(Thread* self) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (self->IsExceptionPending()) { + // If it is not an InternalError, wrap it. + std::string type(PrettyTypeOf(self->GetException())); + if (type != "java.lang.InternalError") { + self->ThrowNewWrappedException("Ljava/lang/ClassNotFoundException;", + "ClassNotFoundException"); + } + } +} + +static void UnstartedClassForName(Thread* self, ShadowFrame* shadow_frame, JValue* result, + size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString(); + StackHandleScope<1> hs(self); + Handle h_class_name(hs.NewHandle(class_name)); + UnstartedRuntimeFindClass(self, h_class_name, NullHandle(), result, + "Class.forName", true, false); + CheckExceptionGenerateClassNotFound(self); +} + +static void UnstartedClassForNameLong(Thread* self, ShadowFrame* shadow_frame, JValue* result, + size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString(); + bool initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0; + mirror::ClassLoader* class_loader = + down_cast(shadow_frame->GetVRegReference(arg_offset + 2)); + StackHandleScope<2> hs(self); + Handle h_class_name(hs.NewHandle(class_name)); + Handle h_class_loader(hs.NewHandle(class_loader)); + UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, "Class.forName", + initialize_class, false); + CheckExceptionGenerateClassNotFound(self); +} + +static void UnstartedClassClassForName(Thread* self, ShadowFrame* shadow_frame, JValue* result, + size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset)->AsString(); + bool initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0; + mirror::ClassLoader* class_loader = + down_cast(shadow_frame->GetVRegReference(arg_offset + 2)); + StackHandleScope<2> hs(self); + Handle h_class_name(hs.NewHandle(class_name)); + Handle h_class_loader(hs.NewHandle(class_loader)); + UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, "Class.classForName", + initialize_class, false); + CheckExceptionGenerateClassNotFound(self); +} + +static void UnstartedClassNewInstance(Thread* self, ShadowFrame* shadow_frame, JValue* result, + size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + StackHandleScope<3> hs(self); // Class, constructor, object. + mirror::Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass(); + Handle h_klass(hs.NewHandle(klass)); + // There are two situations in which we'll abort this run. + // 1) If the class isn't yet initialized and initialization fails. + // 2) If we can't find the default constructor. We'll postpone the exception to runtime. + // Note that 2) could likely be handled here, but for safety abort the transaction. + bool ok = false; + if (Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_klass, true, true)) { + Handle h_cons(hs.NewHandle( + h_klass->FindDeclaredDirectMethod("", "()V"))); + if (h_cons.Get() != nullptr) { + Handle h_obj(hs.NewHandle(klass->AllocObject(self))); + CHECK(h_obj.Get() != nullptr); // We don't expect OOM at compile-time. + EnterInterpreterFromInvoke(self, h_cons.Get(), h_obj.Get(), nullptr, nullptr); + if (!self->IsExceptionPending()) { + result->SetL(h_obj.Get()); + ok = true; + } + } else { + self->ThrowNewExceptionF("Ljava/lang/InternalError;", + "Could not find default constructor for '%s'", + PrettyClass(h_klass.Get()).c_str()); + } + } + if (!ok) { + std::string error_msg = StringPrintf("Failed in Class.newInstance for '%s' with %s", + PrettyClass(h_klass.Get()).c_str(), + PrettyTypeOf(self->GetException()).c_str()); + Runtime::Current()->AbortTransactionAndThrowInternalError(self, error_msg); + } +} + +static void UnstartedClassGetDeclaredField(Thread* self, ShadowFrame* shadow_frame, JValue* result, + size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // Special managed code cut-out to allow field lookup in a un-started runtime that'd fail + // going the reflective Dex way. + mirror::Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass(); + mirror::String* name2 = shadow_frame->GetVRegReference(arg_offset + 1)->AsString(); + mirror::ArtField* found = nullptr; + mirror::ObjectArray* fields = klass->GetIFields(); + for (int32_t i = 0; i < fields->GetLength() && found == nullptr; ++i) { + mirror::ArtField* f = fields->Get(i); + if (name2->Equals(f->GetName())) { + found = f; + } + } + if (found == nullptr) { + fields = klass->GetSFields(); + for (int32_t i = 0; i < fields->GetLength() && found == nullptr; ++i) { + mirror::ArtField* f = fields->Get(i); + if (name2->Equals(f->GetName())) { + found = f; + } + } + } + CHECK(found != nullptr) + << "Failed to find field in Class.getDeclaredField in un-started runtime. name=" + << name2->ToModifiedUtf8() << " class=" << PrettyDescriptor(klass); + // TODO: getDeclaredField calls GetType once the field is found to ensure a + // NoClassDefFoundError is thrown if the field's type cannot be resolved. + mirror::Class* jlr_Field = self->DecodeJObject( + WellKnownClasses::java_lang_reflect_Field)->AsClass(); + StackHandleScope<1> hs(self); + Handle field(hs.NewHandle(jlr_Field->AllocNonMovableObject(self))); + CHECK(field.Get() != nullptr); + mirror::ArtMethod* c = jlr_Field->FindDeclaredDirectMethod("", + "(Ljava/lang/reflect/ArtField;)V"); + uint32_t args[1]; + args[0] = StackReference::FromMirrorPtr(found).AsVRegValue(); + EnterInterpreterFromInvoke(self, c, field.Get(), args, nullptr); + result->SetL(field.Get()); +} + +static void UnstartedVmClassLoaderFindLoadedClass(Thread* self, ShadowFrame* shadow_frame, + JValue* result, size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString(); + mirror::ClassLoader* class_loader = + down_cast(shadow_frame->GetVRegReference(arg_offset)); + StackHandleScope<2> hs(self); + Handle h_class_name(hs.NewHandle(class_name)); + Handle h_class_loader(hs.NewHandle(class_loader)); + UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, + "VMClassLoader.findLoadedClass", false, false); + // This might have an error pending. But semantics are to just return null. + if (self->IsExceptionPending()) { + // If it is an InternalError, keep it. See CheckExceptionGenerateClassNotFound. + std::string type(PrettyTypeOf(self->GetException())); + if (type != "java.lang.InternalError") { + self->ClearException(); + } + } +} + +static void UnstartedVoidLookupType(Thread* self ATTRIBUTE_UNUSED, + ShadowFrame* shadow_frame ATTRIBUTE_UNUSED, + JValue* result, + size_t arg_offset ATTRIBUTE_UNUSED) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V')); +} + +static void UnstartedSystemArraycopy(Thread* self, ShadowFrame* shadow_frame, + JValue* result ATTRIBUTE_UNUSED, size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // Special case array copying without initializing System. + mirror::Class* ctype = shadow_frame->GetVRegReference(arg_offset)->GetClass()->GetComponentType(); + jint srcPos = shadow_frame->GetVReg(arg_offset + 1); + jint dstPos = shadow_frame->GetVReg(arg_offset + 3); + jint length = shadow_frame->GetVReg(arg_offset + 4); + if (!ctype->IsPrimitive()) { + mirror::ObjectArray* src = shadow_frame->GetVRegReference(arg_offset)-> + AsObjectArray(); + mirror::ObjectArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)-> + AsObjectArray(); + for (jint i = 0; i < length; ++i) { + dst->Set(dstPos + i, src->Get(srcPos + i)); + } + } else if (ctype->IsPrimitiveChar()) { + mirror::CharArray* src = shadow_frame->GetVRegReference(arg_offset)->AsCharArray(); + mirror::CharArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsCharArray(); + for (jint i = 0; i < length; ++i) { + dst->Set(dstPos + i, src->Get(srcPos + i)); + } + } else if (ctype->IsPrimitiveInt()) { + mirror::IntArray* src = shadow_frame->GetVRegReference(arg_offset)->AsIntArray(); + mirror::IntArray* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsIntArray(); + for (jint i = 0; i < length; ++i) { + dst->Set(dstPos + i, src->Get(srcPos + i)); + } + } else { + std::string tmp = StringPrintf("Unimplemented System.arraycopy for type '%s'", + PrettyDescriptor(ctype).c_str()); + Runtime::Current()->AbortTransactionAndThrowInternalError(self, tmp); + } +} + +static void UnstartedThreadLocalGet(Thread* self, ShadowFrame* shadow_frame, JValue* result, + size_t arg_offset ATTRIBUTE_UNUSED) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + std::string caller(PrettyMethod(shadow_frame->GetLink()->GetMethod())); + bool ok = false; + if (caller == "java.lang.String java.lang.IntegralToString.convertInt" + "(java.lang.AbstractStringBuilder, int)") { + // Allocate non-threadlocal buffer. + result->SetL(mirror::CharArray::Alloc(self, 11)); + ok = true; + } else if (caller == "java.lang.RealToString java.lang.RealToString.getInstance()") { + // Note: RealToString is implemented and used in a different fashion than IntegralToString. + // Conversion is done over an actual object of RealToString (the conversion method is an + // instance method). This means it is not as clear whether it is correct to return a new + // object each time. The caller needs to be inspected by hand to see whether it (incorrectly) + // stores the object for later use. + // See also b/19548084 for a possible rewrite and bringing it in line with IntegralToString. + if (shadow_frame->GetLink()->GetLink() != nullptr) { + std::string caller2(PrettyMethod(shadow_frame->GetLink()->GetLink()->GetMethod())); + if (caller2 == "java.lang.String java.lang.Double.toString(double)") { + // Allocate new object. + StackHandleScope<2> hs(self); + Handle h_real_to_string_class(hs.NewHandle( + shadow_frame->GetLink()->GetMethod()->GetDeclaringClass())); + Handle h_real_to_string_obj(hs.NewHandle( + h_real_to_string_class->AllocObject(self))); + if (h_real_to_string_obj.Get() != nullptr) { + mirror::ArtMethod* init_method = + h_real_to_string_class->FindDirectMethod("", "()V"); + if (init_method == nullptr) { + h_real_to_string_class->DumpClass(LOG(FATAL), mirror::Class::kDumpClassFullDetail); + } else { + JValue invoke_result; + EnterInterpreterFromInvoke(self, init_method, h_real_to_string_obj.Get(), nullptr, + nullptr); + if (!self->IsExceptionPending()) { + result->SetL(h_real_to_string_obj.Get()); + ok = true; + } + } + } + + if (!ok) { + // We'll abort, so clear exception. + self->ClearException(); + } + } + } + } + + if (!ok) { + Runtime::Current()->AbortTransactionAndThrowInternalError(self, + "Could not create RealToString object"); + } +} + +static void UnstartedMathCeil(Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, + JValue* result, size_t arg_offset) { + double in = shadow_frame->GetVRegDouble(arg_offset); + double out; + // Special cases: + // 1) NaN, infinity, +0, -0 -> out := in. All are guaranteed by cmath. + // -1 < in < 0 -> out := -0. + if (-1.0 < in && in < 0) { + out = -0.0; + } else { + out = ceil(in); + } + result->SetD(out); +} + +static void UnstartedArtMethodGetMethodName(Thread* self, ShadowFrame* shadow_frame, + JValue* result, size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::ArtMethod* method = shadow_frame->GetVRegReference(arg_offset)->AsArtMethod(); + result->SetL(method->GetNameAsString(self)); +} + +static void UnstartedObjectHashCode(Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, + JValue* result, size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Object* obj = shadow_frame->GetVRegReference(arg_offset); + result->SetI(obj->IdentityHashCode()); +} + +static void UnstartedDoubleDoubleToRawLongBits(Thread* self ATTRIBUTE_UNUSED, + ShadowFrame* shadow_frame, JValue* result, + size_t arg_offset) { + double in = shadow_frame->GetVRegDouble(arg_offset); + result->SetJ(bit_cast(in)); +} + +static void UnstartedJNIVMRuntimeNewUnpaddedArray(Thread* self, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + int32_t length = args[1]; + DCHECK_GE(length, 0); + mirror::Class* element_class = reinterpret_cast(args[0])->AsClass(); + Runtime* runtime = Runtime::Current(); + mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(self, &element_class); + DCHECK(array_class != nullptr); + gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator(); + result->SetL(mirror::Array::Alloc(self, array_class, length, + array_class->GetComponentSizeShift(), allocator)); +} + +static void UnstartedJNIVMStackGetCallingClassLoader(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args ATTRIBUTE_UNUSED, + JValue* result) { + result->SetL(nullptr); +} + +static void UnstartedJNIVMStackGetStackClass2(Thread* self, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args ATTRIBUTE_UNUSED, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + NthCallerVisitor visitor(self, 3); + visitor.WalkStack(); + if (visitor.caller != nullptr) { + result->SetL(visitor.caller->GetDeclaringClass()); + } +} + +static void UnstartedJNIMathLog(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args, + JValue* result) { + JValue value; + value.SetJ((static_cast(args[1]) << 32) | args[0]); + result->SetD(log(value.GetD())); +} + +static void UnstartedJNIMathExp(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args, + JValue* result) { + JValue value; + value.SetJ((static_cast(args[1]) << 32) | args[0]); + result->SetD(exp(value.GetD())); +} + +static void UnstartedJNIClassGetNameNative(Thread* self, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver, + uint32_t* args ATTRIBUTE_UNUSED, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + StackHandleScope<1> hs(self); + result->SetL(mirror::Class::ComputeName(hs.NewHandle(receiver->AsClass()))); +} + +static void UnstartedJNIFloatFloatToRawIntBits(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args, + JValue* result) { + result->SetI(args[0]); +} + +static void UnstartedJNIFloatIntBitsToFloat(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args, + JValue* result) { + result->SetI(args[0]); +} + +static void UnstartedJNIObjectInternalClone(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver, + uint32_t* args ATTRIBUTE_UNUSED, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + result->SetL(receiver->Clone(self)); +} + +static void UnstartedJNIObjectNotifyAll(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver, + uint32_t* args ATTRIBUTE_UNUSED, + JValue* result ATTRIBUTE_UNUSED) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + receiver->NotifyAll(self); +} + +static void UnstartedJNIStringCompareTo(Thread* self, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver, + uint32_t* args, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::String* rhs = reinterpret_cast(args[0])->AsString(); + if (rhs == nullptr) { + AbortTransaction(self, "String.compareTo with null object"); + } + result->SetI(receiver->AsString()->CompareTo(rhs)); +} + +static void UnstartedJNIStringIntern(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver, + uint32_t* args ATTRIBUTE_UNUSED, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + result->SetL(receiver->AsString()->Intern()); +} + +static void UnstartedJNIStringFastIndexOf(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver, + uint32_t* args, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + result->SetI(receiver->AsString()->FastIndexOf(args[0], args[1])); +} + +static void UnstartedJNIArrayCreateMultiArray(Thread* self, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + StackHandleScope<2> hs(self); + auto h_class(hs.NewHandle(reinterpret_cast(args[0])->AsClass())); + auto h_dimensions(hs.NewHandle(reinterpret_cast(args[1])->AsIntArray())); + result->SetL(mirror::Array::CreateMultiArray(self, h_class, h_dimensions)); +} + +static void UnstartedJNIThrowableNativeFillInStackTrace(Thread* self, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args ATTRIBUTE_UNUSED, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + ScopedObjectAccessUnchecked soa(self); + if (Runtime::Current()->IsActiveTransaction()) { + result->SetL(soa.Decode(self->CreateInternalStackTrace(soa))); + } else { + result->SetL(soa.Decode(self->CreateInternalStackTrace(soa))); + } +} + +static void UnstartedJNISystemIdentityHashCode(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Object* obj = reinterpret_cast(args[0]); + result->SetI((obj != nullptr) ? obj->IdentityHashCode() : 0); +} + +static void UnstartedJNIByteOrderIsLittleEndian(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args ATTRIBUTE_UNUSED, + JValue* result) { + result->SetZ(JNI_TRUE); +} + +static void UnstartedJNIUnsafeCompareAndSwapInt(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Object* obj = reinterpret_cast(args[0]); + jlong offset = (static_cast(args[2]) << 32) | args[1]; + jint expectedValue = args[3]; + jint newValue = args[4]; + bool success; + if (Runtime::Current()->IsActiveTransaction()) { + success = obj->CasFieldStrongSequentiallyConsistent32(MemberOffset(offset), + expectedValue, newValue); + } else { + success = obj->CasFieldStrongSequentiallyConsistent32(MemberOffset(offset), + expectedValue, newValue); + } + result->SetZ(success ? JNI_TRUE : JNI_FALSE); +} + +static void UnstartedJNIUnsafePutObject(Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args, + JValue* result ATTRIBUTE_UNUSED) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Object* obj = reinterpret_cast(args[0]); + jlong offset = (static_cast(args[2]) << 32) | args[1]; + mirror::Object* newValue = reinterpret_cast(args[3]); + if (Runtime::Current()->IsActiveTransaction()) { + obj->SetFieldObject(MemberOffset(offset), newValue); + } else { + obj->SetFieldObject(MemberOffset(offset), newValue); + } +} + +static void UnstartedJNIUnsafeGetArrayBaseOffsetForComponentType( + Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Class* component = reinterpret_cast(args[0])->AsClass(); + Primitive::Type primitive_type = component->GetPrimitiveType(); + result->SetI(mirror::Array::DataOffset(Primitive::ComponentSize(primitive_type)).Int32Value()); +} + +static void UnstartedJNIUnsafeGetArrayIndexScaleForComponentType( + Thread* self ATTRIBUTE_UNUSED, + mirror::ArtMethod* method ATTRIBUTE_UNUSED, + mirror::Object* receiver ATTRIBUTE_UNUSED, + uint32_t* args, + JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::Class* component = reinterpret_cast(args[0])->AsClass(); + Primitive::Type primitive_type = component->GetPrimitiveType(); + result->SetI(Primitive::ComponentSize(primitive_type)); +} + +typedef void(*InvokeHandler)(Thread* self, ShadowFrame* shadow_frame, JValue* result, + size_t arg_size); + +typedef void(*JNIHandler)(Thread* self, mirror::ArtMethod* method, mirror::Object* receiver, + uint32_t* args, JValue* result); + +static bool tables_initialized_ = false; +static std::unordered_map invoke_handlers_; +static std::unordered_map jni_handlers_; + +static void UnstartedRuntimeInitializeInvokeHandlers() { + struct InvokeHandlerDef { + std::string name; + InvokeHandler function; + }; + + InvokeHandlerDef defs[] { + { "java.lang.Class java.lang.Class.forName(java.lang.String)", + &UnstartedClassForName }, + { "java.lang.Class java.lang.Class.forName(java.lang.String, boolean, java.lang.ClassLoader)", + &UnstartedClassForNameLong }, + { "java.lang.Class java.lang.Class.classForName(java.lang.String, boolean, java.lang.ClassLoader)", + &UnstartedClassClassForName }, + { "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)", + &UnstartedVmClassLoaderFindLoadedClass }, + { "java.lang.Class java.lang.Void.lookupType()", + &UnstartedVoidLookupType }, + { "java.lang.Object java.lang.Class.newInstance()", + &UnstartedClassNewInstance }, + { "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)", + &UnstartedClassGetDeclaredField }, + { "int java.lang.Object.hashCode()", + &UnstartedObjectHashCode }, + { "java.lang.String java.lang.reflect.ArtMethod.getMethodName(java.lang.reflect.ArtMethod)", + &UnstartedArtMethodGetMethodName }, + { "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)", + &UnstartedSystemArraycopy}, + { "void java.lang.System.arraycopy(char[], int, char[], int, int)", + &UnstartedSystemArraycopy }, + { "void java.lang.System.arraycopy(int[], int, int[], int, int)", + &UnstartedSystemArraycopy }, + { "long java.lang.Double.doubleToRawLongBits(double)", + &UnstartedDoubleDoubleToRawLongBits }, + { "double java.lang.Math.ceil(double)", + &UnstartedMathCeil }, + { "java.lang.Object java.lang.ThreadLocal.get()", + &UnstartedThreadLocalGet }, + }; + + for (auto& def : defs) { + invoke_handlers_.insert(std::make_pair(def.name, def.function)); + } +} + +static void UnstartedRuntimeInitializeJNIHandlers() { + struct JNIHandlerDef { + std::string name; + JNIHandler function; + }; + + JNIHandlerDef defs[] { + { "java.lang.Object dalvik.system.VMRuntime.newUnpaddedArray(java.lang.Class, int)", + &UnstartedJNIVMRuntimeNewUnpaddedArray }, + { "java.lang.ClassLoader dalvik.system.VMStack.getCallingClassLoader()", + &UnstartedJNIVMStackGetCallingClassLoader }, + { "java.lang.Class dalvik.system.VMStack.getStackClass2()", + &UnstartedJNIVMStackGetStackClass2 }, + { "double java.lang.Math.log(double)", + &UnstartedJNIMathLog }, + { "java.lang.String java.lang.Class.getNameNative()", + &UnstartedJNIClassGetNameNative }, + { "int java.lang.Float.floatToRawIntBits(float)", + &UnstartedJNIFloatFloatToRawIntBits }, + { "float java.lang.Float.intBitsToFloat(int)", + &UnstartedJNIFloatIntBitsToFloat }, + { "double java.lang.Math.exp(double)", + &UnstartedJNIMathExp }, + { "java.lang.Object java.lang.Object.internalClone()", + &UnstartedJNIObjectInternalClone }, + { "void java.lang.Object.notifyAll()", + &UnstartedJNIObjectNotifyAll}, + { "int java.lang.String.compareTo(java.lang.String)", + &UnstartedJNIStringCompareTo }, + { "java.lang.String java.lang.String.intern()", + &UnstartedJNIStringIntern }, + { "int java.lang.String.fastIndexOf(int, int)", + &UnstartedJNIStringFastIndexOf }, + { "java.lang.Object java.lang.reflect.Array.createMultiArray(java.lang.Class, int[])", + &UnstartedJNIArrayCreateMultiArray }, + { "java.lang.Object java.lang.Throwable.nativeFillInStackTrace()", + &UnstartedJNIThrowableNativeFillInStackTrace }, + { "int java.lang.System.identityHashCode(java.lang.Object)", + &UnstartedJNISystemIdentityHashCode }, + { "boolean java.nio.ByteOrder.isLittleEndian()", + &UnstartedJNIByteOrderIsLittleEndian }, + { "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)", + &UnstartedJNIUnsafeCompareAndSwapInt }, + { "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)", + &UnstartedJNIUnsafePutObject }, + { "int sun.misc.Unsafe.getArrayBaseOffsetForComponentType(java.lang.Class)", + &UnstartedJNIUnsafeGetArrayBaseOffsetForComponentType }, + { "int sun.misc.Unsafe.getArrayIndexScaleForComponentType(java.lang.Class)", + &UnstartedJNIUnsafeGetArrayIndexScaleForComponentType }, + }; + + for (auto& def : defs) { + jni_handlers_.insert(std::make_pair(def.name, def.function)); + } +} + +void UnstartedRuntimeInitialize() { + CHECK(!tables_initialized_); + + UnstartedRuntimeInitializeInvokeHandlers(); + UnstartedRuntimeInitializeJNIHandlers(); + + tables_initialized_ = true; +} + +void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { + // In a runtime that's not started we intercept certain methods to avoid complicated dependency + // problems in core libraries. + CHECK(tables_initialized_); + + std::string name(PrettyMethod(shadow_frame->GetMethod())); + const auto& iter = invoke_handlers_.find(name); + if (iter != invoke_handlers_.end()) { + (*iter->second)(self, shadow_frame, result, arg_offset); + } else { + // Not special, continue with regular interpreter execution. + artInterpreterToInterpreterBridge(self, code_item, shadow_frame, result); + } +} + +// Hand select a number of methods to be run in a not yet started runtime without using JNI. +void UnstartedRuntimeJni(Thread* self, mirror::ArtMethod* method, mirror::Object* receiver, + uint32_t* args, JValue* result) { + std::string name(PrettyMethod(method)); + const auto& iter = jni_handlers_.find(name); + if (iter != jni_handlers_.end()) { + (*iter->second)(self, method, receiver, args, result); + } else if (Runtime::Current()->IsActiveTransaction()) { + AbortTransaction(self, "Attempt to invoke native method in non-started runtime: %s", + name.c_str()); + } else { + LOG(FATAL) << "Calling native method " << PrettyMethod(method) << " in an unstarted " + "non-transactional runtime"; + } +} + +} // namespace interpreter +} // namespace art diff --git a/runtime/interpreter/unstarted_runtime.h b/runtime/interpreter/unstarted_runtime.h new file mode 100644 index 000000000..2d7d38011 --- /dev/null +++ b/runtime/interpreter/unstarted_runtime.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_INTERPRETER_UNSTARTED_RUNTIME_H_ +#define ART_RUNTIME_INTERPRETER_UNSTARTED_RUNTIME_H_ + +#include "interpreter.h" + +#include "dex_file.h" +#include "jvalue.h" + +namespace art { + +class Thread; +class ShadowFrame; + +namespace mirror { + +class ArtMethod; +class Object; + +} // namespace mirror + +namespace interpreter { + +void UnstartedRuntimeInitialize(); + +void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, + JValue* result, size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + +void UnstartedRuntimeJni(Thread* self, mirror::ArtMethod* method, mirror::Object* receiver, + uint32_t* args, JValue* result) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + +} // namespace interpreter +} // namespace art + +#endif // ART_RUNTIME_INTERPRETER_UNSTARTED_RUNTIME_H_ diff --git a/runtime/transaction.cc b/runtime/transaction.cc index 2199021c8..3b708f6d8 100644 --- a/runtime/transaction.cc +++ b/runtime/transaction.cc @@ -75,7 +75,7 @@ void Transaction::ThrowInternalError(Thread* self, bool rethrow) { CHECK(IsAborted()) << "Rethrow InternalError while transaction is not aborted"; } std::string abort_msg(GetAbortMessage()); - self->ThrowNewException("Ljava/lang/InternalError;", abort_msg.c_str()); + self->ThrowNewWrappedException("Ljava/lang/InternalError;", abort_msg.c_str()); } bool Transaction::IsAborted() { -- 2.11.0