diff options
| -rw-r--r-- | runtime/interpreter/unstarted_runtime.cc | 66 | ||||
| -rw-r--r-- | runtime/interpreter/unstarted_runtime_list.h | 1 | ||||
| -rw-r--r-- | runtime/interpreter/unstarted_runtime_test.cc | 50 |
3 files changed, 117 insertions, 0 deletions
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 4a321e6d27..af0478c1eb 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -632,6 +632,72 @@ void UnstartedRuntime::UnstartedClassLoaderGetResourceAsStream( GetResourceAsStream(self, shadow_frame, result, arg_offset); } +void UnstartedRuntime::UnstartedConstructorNewInstance0( + Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { + // This is a cutdown version of java_lang_reflect_Constructor.cc's implementation. + StackHandleScope<4> hs(self); + Handle<mirror::Constructor> m = hs.NewHandle( + reinterpret_cast<mirror::Constructor*>(shadow_frame->GetVRegReference(arg_offset))); + Handle<mirror::ObjectArray<mirror::Object>> args = hs.NewHandle( + reinterpret_cast<mirror::ObjectArray<mirror::Object>*>( + shadow_frame->GetVRegReference(arg_offset + 1))); + Handle<mirror::Class> c(hs.NewHandle(m->GetDeclaringClass())); + if (UNLIKELY(c->IsAbstract())) { + AbortTransactionOrFail(self, "Cannot handle abstract classes"); + return; + } + // Verify that we can access the class. + if (!m->IsAccessible() && !c->IsPublic()) { + // Go 2 frames back, this method is always called from newInstance0, which is called from + // Constructor.newInstance(Object... args). + ObjPtr<mirror::Class> caller = GetCallingClass(self, 2); + // If caller is null, then we called from JNI, just avoid the check since JNI avoids most + // access checks anyways. TODO: Investigate if this the correct behavior. + if (caller != nullptr && !caller->CanAccess(c.Get())) { + AbortTransactionOrFail(self, "Cannot access class"); + return; + } + } + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, c, true, true)) { + DCHECK(self->IsExceptionPending()); + return; + } + if (c->IsClassClass()) { + AbortTransactionOrFail(self, "new Class() is not supported"); + return; + } + + // String constructor is replaced by a StringFactory method in InvokeMethod. + if (c->IsStringClass()) { + // We don't support strings. + AbortTransactionOrFail(self, "String construction is not supported"); + return; + } + + Handle<mirror::Object> receiver = hs.NewHandle(c->AllocObject(self)); + if (receiver == nullptr) { + AbortTransactionOrFail(self, "Could not allocate"); + return; + } + + // It's easier to use reflection to make the call, than create the uint32_t array. + { + ScopedObjectAccessUnchecked soa(self); + ScopedLocalRef<jobject> method_ref(self->GetJniEnv(), + soa.AddLocalReference<jobject>(m.Get())); + ScopedLocalRef<jobject> object_ref(self->GetJniEnv(), + soa.AddLocalReference<jobject>(receiver.Get())); + ScopedLocalRef<jobject> args_ref(self->GetJniEnv(), + soa.AddLocalReference<jobject>(args.Get())); + InvokeMethod(soa, method_ref.get(), object_ref.get(), args_ref.get(), 2); + } + if (self->IsExceptionPending()) { + AbortTransactionOrFail(self, "Failed running constructor"); + } else { + result->SetL(receiver.Get()); + } +} + void UnstartedRuntime::UnstartedVmClassLoaderFindLoadedClass( Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString(); diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h index c6114da037..6fc7989acf 100644 --- a/runtime/interpreter/unstarted_runtime_list.h +++ b/runtime/interpreter/unstarted_runtime_list.h @@ -34,6 +34,7 @@ V(ClassGetSignatureAnnotation, "java.lang.String[] java.lang.Class.getSignatureAnnotation()") \ V(ClassIsAnonymousClass, "boolean java.lang.Class.isAnonymousClass()") \ V(ClassLoaderGetResourceAsStream, "java.io.InputStream java.lang.ClassLoader.getResourceAsStream(java.lang.String)") \ + V(ConstructorNewInstance0, "java.lang.Object java.lang.reflect.Constructor.newInstance0(java.lang.Object[])") \ V(VmClassLoaderFindLoadedClass, "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") \ V(VoidLookupType, "java.lang.Class java.lang.Void.lookupType()") \ V(SystemArraycopy, "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)") \ diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc index 4186c37dbc..db222fad6d 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -1317,5 +1317,55 @@ TEST_F(UnstartedRuntimeTest, ClassGetSignatureAnnotation) { ASSERT_EQ(output_string, "<E:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/Collection<TE;>;"); } +TEST_F(UnstartedRuntimeTest, ConstructorNewInstance0) { + Thread* self = Thread::Current(); + ScopedObjectAccess soa(self); + + StackHandleScope<4> hs(self); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + + // Get Throwable. + Handle<mirror::Class> throw_class = hs.NewHandle(mirror::Throwable::GetJavaLangThrowable()); + ASSERT_TRUE(class_linker->EnsureInitialized(self, throw_class, true, true)); + + // Get an input object. + Handle<mirror::String> input = hs.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "abd")); + + // Find the constructor. + ArtMethod* throw_cons = throw_class->FindDeclaredDirectMethod( + "<init>", "(Ljava/lang/String;)V", class_linker->GetImagePointerSize()); + ASSERT_TRUE(throw_cons != nullptr); + + Handle<mirror::Constructor> cons = hs.NewHandle( + mirror::Constructor::CreateFromArtMethod<kRuntimePointerSize, false>(self, throw_cons)); + ASSERT_TRUE(cons != nullptr); + + Handle<mirror::ObjectArray<mirror::Object>> args = hs.NewHandle( + class_linker->AllocObjectArray<mirror::Object>(self, 1)); + ASSERT_TRUE(args != nullptr); + args->Set(0, input.Get()); + + // OK, we're ready now. + JValue result; + ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0); + shadow_frame->SetVRegReference(0, cons.Get()); + shadow_frame->SetVRegReference(1, args.Get()); + UnstartedConstructorNewInstance0(self, shadow_frame, &result, 0); + + ASSERT_TRUE(result.GetL() != nullptr); + ASSERT_FALSE(self->IsExceptionPending()); + + // Should be a new object. + ASSERT_NE(result.GetL(), input.Get()); + // Should be a String. + ASSERT_EQ(mirror::Throwable::GetJavaLangThrowable(), result.GetL()->GetClass()); + // Should have the right string. + ObjPtr<mirror::String> result_msg = + reinterpret_cast<mirror::Throwable*>(result.GetL())->GetDetailMessage(); + EXPECT_EQ(input.Get(), result_msg.Ptr()); + + ShadowFrame::DeleteDeoptimizedFrame(shadow_frame); +} + } // namespace interpreter } // namespace art |