summaryrefslogtreecommitdiffstats
path: root/runtime/interpreter
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2015-02-27 20:08:34 -0800
committerAndreas Gampe <agampe@google.com>2015-03-02 10:16:43 -0800
commitf0e128a41154642f470eae0c7c57476efb527cd1 (patch)
tree163083fe9eac8e79c94da4d00707aeddc9f66411 /runtime/interpreter
parentf90316e06e1c7b7b4a4ebea8de0a1b4d72228fd6 (diff)
downloadart-f0e128a41154642f470eae0c7c57476efb527cd1.zip
art-f0e128a41154642f470eae0c7c57476efb527cd1.tar.gz
art-f0e128a41154642f470eae0c7c57476efb527cd1.tar.bz2
ART: Allow more operations in unstarted Runtime
To compile-time initialize more classes, have more dedicated code for special methods. Bug: 19542228 Bug: 19548084 Change-Id: Iad37c1c58302b04fa3a5a904a923da388a079cd7
Diffstat (limited to 'runtime/interpreter')
-rw-r--r--runtime/interpreter/interpreter_common.cc150
1 files changed, 135 insertions, 15 deletions
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index a29558e..3ab7f30 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -16,6 +16,8 @@
#include "interpreter_common.h"
+#include <cmath>
+
#include "mirror/array-inl.h"
namespace art {
@@ -839,6 +841,23 @@ static void UnstartedRuntimeFindClass(Thread* self, Handle<mirror::String> class
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(nullptr)));
+ if (type != "java.lang.InternalError") {
+ self->ThrowNewWrappedException(self->GetCurrentLocationForThrow(),
+ "Ljava/lang/ClassNotFoundException;",
+ "ClassNotFoundException");
+ }
+ }
+}
+
static void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame,
JValue* result, size_t arg_offset) {
@@ -846,18 +865,34 @@ static void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_
// problems in core libraries.
std::string name(PrettyMethod(shadow_frame->GetMethod()));
if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
- // TODO: Support for the other variants that take more arguments should also be added.
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, true);
- } else if (name == "java.lang.Class java.lang.VMClassLoader.loadClass(java.lang.String, boolean)") {
+ 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();
- StackHandleScope<1> hs(self);
+ 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));
- UnstartedRuntimeFindClass(self, h_class_name, NullHandle<mirror::ClassLoader>(), result, name,
- false, true);
+ 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 =
@@ -866,17 +901,47 @@ static void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_
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(nullptr)));
+ 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<2> hs(self);
Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
- ArtMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V");
- CHECK(c != NULL);
- StackHandleScope<1> hs(self);
- Handle<Object> obj(hs.NewHandle(klass->AllocObject(self)));
- CHECK(obj.Get() != NULL);
- EnterInterpreterFromInvoke(self, c, obj.Get(), NULL, NULL);
- result->SetL(obj.Get());
+ 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)) {
+ ArtMethod* c = h_klass->FindDeclaredDirectMethod("<init>", "()V");
+ if (c != nullptr) {
+ Handle<Object> obj(hs.NewHandle(klass->AllocObject(self)));
+ CHECK(obj.Get() != nullptr); // We don't expect OOM at compile-time.
+ EnterInterpreterFromInvoke(self, c, obj.Get(), nullptr, nullptr);
+ result->SetL(obj.Get());
+ ok = true;
+ } else {
+ self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(), "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(nullptr)).c_str());
+ self->ThrowNewWrappedException(self->GetCurrentLocationForThrow(),
+ "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.
@@ -949,12 +1014,67 @@ static void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_
"Unimplemented System.arraycopy for type '%s'",
PrettyDescriptor(ctype).c_str());
}
- } else if (name == "java.lang.Object java.lang.ThreadLocal.get()") {
+ } 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));
- } else {
+ 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.
+ mirror::Class* real_to_string_class =
+ shadow_frame->GetLink()->GetMethod()->GetDeclaringClass();
+ mirror::Object* real_to_string_obj = real_to_string_class->AllocObject(self);
+ if (real_to_string_obj != nullptr) {
+ mirror::ArtMethod* init_method =
+ real_to_string_class->FindDirectMethod("<init>", "()V");
+ if (init_method == nullptr) {
+ real_to_string_class->DumpClass(LOG(FATAL), mirror::Class::kDumpClassFullDetail);
+ }
+ JValue invoke_result;
+ // One arg, this.
+ uint32_t args = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(real_to_string_obj));
+ init_method->Invoke(self, &args, 4, &invoke_result, init_method->GetShorty());
+ if (!self->IsExceptionPending()) {
+ result->SetL(real_to_string_obj);
+ ok = true;
+ }
+ }
+
+ if (!ok) {
+ // We'll abort, so clear exception.
+ self->ClearException();
+ }
+ }
+ }
+ }
+
+ if (!ok) {
self->ThrowNewException(self->GetCurrentLocationForThrow(), "Ljava/lang/InternalError;",
"Unimplemented ThreadLocal.get");
}