summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2015-03-09 12:57:41 -0700
committerAndreas Gampe <agampe@google.com>2015-03-11 09:27:03 -0700
commit2969bcdcd80624e4a4fef696b54c2c76b44b6853 (patch)
treea097d139d5525ec2af6682f3e37bda94dead8cc9
parentf719fdd20e6282f3579cb99529bb65e852612647 (diff)
downloadart-2969bcdcd80624e4a4fef696b54c2c76b44b6853.zip
art-2969bcdcd80624e4a4fef696b54c2c76b44b6853.tar.gz
art-2969bcdcd80624e4a4fef696b54c2c76b44b6853.tar.bz2
ART: Refactor unstarted runtime
Refactor and clean up unstarted runtime. Bug: 19542228 Change-Id: Ib3e4b3517e06e8242d4fed32ca59419fef553a47
-rw-r--r--dex2oat/dex2oat.cc7
-rw-r--r--runtime/Android.mk1
-rw-r--r--runtime/common_runtime_test.cc5
-rw-r--r--runtime/interpreter/interpreter.cc109
-rw-r--r--runtime/interpreter/interpreter_common.cc278
-rw-r--r--runtime/interpreter/interpreter_common.h7
-rw-r--r--runtime/interpreter/unstarted_runtime.cc752
-rw-r--r--runtime/interpreter/unstarted_runtime.h53
-rw-r--r--runtime/transaction.cc2
9 files changed, 823 insertions, 391 deletions
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index c3303e1..bb80a70 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 af0c479..8f20381 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 8dd9a46..ceae9e8 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 9d988e9..686b518 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -19,116 +19,13 @@
#include <limits>
#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<Object*>(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<true, true>(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<uint64_t>(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<uint64_t>(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<Object*>(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<mirror::Class*>(args[0])->AsClass()));
- auto h_dimensions(hs.NewHandle(reinterpret_cast<mirror::IntArray*>(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<Object*>(self->CreateInternalStackTrace<true>(soa)));
- } else {
- result->SetL(soa.Decode<Object*>(self->CreateInternalStackTrace<false>(soa)));
- }
- } else if (name == "int java.lang.System.identityHashCode(java.lang.Object)") {
- mirror::Object* obj = reinterpret_cast<Object*>(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<Object*>(args[0]);
- jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
- jint expectedValue = args[3];
- jint newValue = args[4];
- bool success;
- if (Runtime::Current()->IsActiveTransaction()) {
- success = obj->CasFieldStrongSequentiallyConsistent32<true>(MemberOffset(offset),
- expectedValue, newValue);
- } else {
- success = obj->CasFieldStrongSequentiallyConsistent32<false>(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<Object*>(args[0]);
- jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
- Object* newValue = reinterpret_cast<Object*>(args[3]);
- if (Runtime::Current()->IsActiveTransaction()) {
- obj->SetFieldObject<true>(MemberOffset(offset), newValue);
- } else {
- obj->SetFieldObject<false>(MemberOffset(offset), newValue);
- }
- } else if (name == "int sun.misc.Unsafe.getArrayBaseOffsetForComponentType(java.lang.Class)") {
- mirror::Class* component = reinterpret_cast<Object*>(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<Object*>(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 2a9c0d4..26ab602 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -19,6 +19,7 @@
#include <cmath>
#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<mirror::String> className,
- Handle<mirror::ClassLoader> 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<mirror::Class> 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<mirror::String> h_class_name(hs.NewHandle(class_name));
- UnstartedRuntimeFindClass(self, h_class_name, NullHandle<mirror::ClassLoader>(), 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<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset + 2));
- StackHandleScope<2> hs(self);
- Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
- Handle<mirror::ClassLoader> 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<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset + 2));
- StackHandleScope<2> hs(self);
- Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
- Handle<mirror::ClassLoader> 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<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset));
- StackHandleScope<2> hs(self);
- Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
- Handle<mirror::ClassLoader> 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<Class> 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<ArtMethod> h_cons(hs.NewHandle(h_klass->FindDeclaredDirectMethod("<init>", "()V")));
- if (h_cons.Get() != nullptr) {
- Handle<Object> 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<ArtField>* 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<Object> field(hs.NewHandle(jlr_Field->AllocNonMovableObject(self)));
- CHECK(field.Get() != NULL);
- ArtMethod* c = jlr_Field->FindDeclaredDirectMethod("<init>", "(Ljava/lang/reflect/ArtField;)V");
- uint32_t args[1];
- 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)") {
- 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<Object>* src = shadow_frame->GetVRegReference(arg_offset)->AsObjectArray<Object>();
- ObjectArray<Object>* dst = shadow_frame->GetVRegReference(arg_offset + 2)->AsObjectArray<Object>();
- 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<int64_t>(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<Class> h_real_to_string_class(hs.NewHandle(
- shadow_frame->GetLink()->GetMethod()->GetDeclaringClass()));
- Handle<Object> 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("<init>", "()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 3095316..15396d6 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 0000000..99ce1e2
--- /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 <cmath>
+#include <unordered_map>
+
+#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<mirror::String> className,
+ Handle<mirror::ClassLoader> 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<mirror::Class> 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<mirror::String> h_class_name(hs.NewHandle(class_name));
+ UnstartedRuntimeFindClass(self, h_class_name, NullHandle<mirror::ClassLoader>(), 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<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset + 2));
+ StackHandleScope<2> hs(self);
+ Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
+ Handle<mirror::ClassLoader> 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<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset + 2));
+ StackHandleScope<2> hs(self);
+ Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
+ Handle<mirror::ClassLoader> 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<mirror::Class> 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<mirror::ArtMethod> h_cons(hs.NewHandle(
+ h_klass->FindDeclaredDirectMethod("<init>", "()V")));
+ if (h_cons.Get() != nullptr) {
+ Handle<mirror::Object> 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<mirror::ArtField>* 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<mirror::Object> field(hs.NewHandle(jlr_Field->AllocNonMovableObject(self)));
+ CHECK(field.Get() != nullptr);
+ mirror::ArtMethod* c = jlr_Field->FindDeclaredDirectMethod("<init>",
+ "(Ljava/lang/reflect/ArtField;)V");
+ uint32_t args[1];
+ args[0] = StackReference<mirror::Object>::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<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset));
+ StackHandleScope<2> hs(self);
+ Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
+ Handle<mirror::ClassLoader> 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<mirror::Object>* src = shadow_frame->GetVRegReference(arg_offset)->
+ AsObjectArray<mirror::Object>();
+ mirror::ObjectArray<mirror::Object>* dst = shadow_frame->GetVRegReference(arg_offset + 2)->
+ AsObjectArray<mirror::Object>();
+ 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<mirror::Class> h_real_to_string_class(hs.NewHandle(
+ shadow_frame->GetLink()->GetMethod()->GetDeclaringClass()));
+ Handle<mirror::Object> 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("<init>", "()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<int64_t>(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<mirror::Object*>(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<true, true>(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<uint64_t>(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<uint64_t>(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<mirror::Object*>(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<mirror::Class*>(args[0])->AsClass()));
+ auto h_dimensions(hs.NewHandle(reinterpret_cast<mirror::IntArray*>(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<mirror::Object*>(self->CreateInternalStackTrace<true>(soa)));
+ } else {
+ result->SetL(soa.Decode<mirror::Object*>(self->CreateInternalStackTrace<false>(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<mirror::Object*>(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<mirror::Object*>(args[0]);
+ jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
+ jint expectedValue = args[3];
+ jint newValue = args[4];
+ bool success;
+ if (Runtime::Current()->IsActiveTransaction()) {
+ success = obj->CasFieldStrongSequentiallyConsistent32<true>(MemberOffset(offset),
+ expectedValue, newValue);
+ } else {
+ success = obj->CasFieldStrongSequentiallyConsistent32<false>(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<mirror::Object*>(args[0]);
+ jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
+ mirror::Object* newValue = reinterpret_cast<mirror::Object*>(args[3]);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ obj->SetFieldObject<true>(MemberOffset(offset), newValue);
+ } else {
+ obj->SetFieldObject<false>(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<mirror::Object*>(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<mirror::Object*>(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<std::string, InvokeHandler> invoke_handlers_;
+static std::unordered_map<std::string, JNIHandler> 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 0000000..2d7d380
--- /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 2199021..3b708f6 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() {