blob: 63d6cccedb7d6d84c184f51d70ec2d485d04e5f2 [file] [log] [blame]
Igor Murashkin457e8742015-10-22 17:37:50 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <jni.h>
18#include <vector>
19
20#include "art_field-inl.h"
21#include "class_linker-inl.h"
22#include "compiler_callbacks.h"
23#include "common_compiler_test.h"
24#include "mirror/field-inl.h"
25#include "mirror/lambda_proxy.h"
26#include "mirror/method.h"
27#include "scoped_thread_state_change.h"
28
29namespace art {
30
31// The enclosing class of all the interfaces used by this test.
32// -- Defined as a macro to allow for string concatenation.
33#define TEST_INTERFACE_ENCLOSING_CLASS_NAME "LambdaInterfaces"
34// Generate out "LLambdaInterfaces$<<iface>>;" , replacing <<iface>> with the interface name.
35#define MAKE_TEST_INTERFACE_NAME(iface) ("L" TEST_INTERFACE_ENCLOSING_CLASS_NAME "$" iface ";")
36
37#define ASSERT_NOT_NULL(x) ASSERT_TRUE((x) != nullptr)
38#define ASSERT_NULL(x) ASSERT_TRUE((x) == nullptr)
39#define EXPECT_NULL(x) EXPECT_TRUE((x) == nullptr)
40
41class LambdaProxyTest // : public CommonCompilerTest {
42 : public CommonRuntimeTest {
43 public:
44 // Generate a lambda proxy class with the given name and interfaces. This is a simplification from what
45 // libcore does to fit to our test needs. We do not check for duplicated interfaces or methods and
46 // we do not declare exceptions.
47 mirror::Class* GenerateProxyClass(ScopedObjectAccess& soa,
48 jobject jclass_loader,
49 const char* class_name,
50 const std::vector<mirror::Class*>& interfaces)
51 SHARED_REQUIRES(Locks::mutator_lock_) {
52 CHECK(class_name != nullptr);
53 CHECK(jclass_loader != nullptr);
54
55 mirror::Class* java_lang_object =
56 class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
57 CHECK(java_lang_object != nullptr);
58
59 jclass java_lang_class = soa.AddLocalReference<jclass>(mirror::Class::GetJavaLangClass());
60
61 // Builds the interfaces array.
62 jobjectArray proxy_class_interfaces = soa.Env()->NewObjectArray(interfaces.size(),
63 java_lang_class,
64 nullptr); // No initial element.
65 soa.Self()->AssertNoPendingException();
66 for (size_t i = 0; i < interfaces.size(); ++i) {
67 soa.Env()->SetObjectArrayElement(proxy_class_interfaces,
68 i,
69 soa.AddLocalReference<jclass>(interfaces[i]));
70 }
71
72 // Builds the method array.
73 jsize methods_count = 3; // Object.equals, Object.hashCode and Object.toString.
74 for (mirror::Class* interface : interfaces) {
75 methods_count += interface->NumVirtualMethods();
76 }
77 jobjectArray proxy_class_methods =
78 soa.Env()->NewObjectArray(methods_count,
79 soa.AddLocalReference<jclass>(mirror::Method::StaticClass()),
80 nullptr); // No initial element.
81 soa.Self()->AssertNoPendingException();
82
83 jsize array_index = 0;
84
85 //
86 // Fill the method array with the Object and all the interface's virtual methods.
87 //
88
89 // Add a method to 'proxy_class_methods'
90 auto add_method_to_array = [&](ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_) {
91 CHECK(method != nullptr);
92 soa.Env()->SetObjectArrayElement(proxy_class_methods,
93 array_index++,
94 soa.AddLocalReference<jobject>(
95 mirror::Method::CreateFromArtMethod(soa.Self(),
96 method))
97 ); // NOLINT: [whitespace/parens] [2]
98
99 LOG(DEBUG) << "Add " << PrettyMethod(method) << " to list of methods to generate proxy";
100 };
101 // Add a method to 'proxy_class_methods' by looking it up from java.lang.Object
102 auto add_method_to_array_by_lookup = [&](const char* name, const char* method_descriptor)
103 SHARED_REQUIRES(Locks::mutator_lock_) {
104 ArtMethod* method = java_lang_object->FindDeclaredVirtualMethod(name,
105 method_descriptor,
106 sizeof(void*));
107 add_method_to_array(method);
108 };
109
110 // Add all methods from Object.
111 add_method_to_array_by_lookup("equals", "(Ljava/lang/Object;)Z");
112 add_method_to_array_by_lookup("hashCode", "()I");
113 add_method_to_array_by_lookup("toString", "()Ljava/lang/String;");
114
115 // Now adds all interfaces virtual methods.
116 for (mirror::Class* interface : interfaces) {
117 mirror::Class* next_class = interface;
118 do {
119 for (ArtMethod& method : next_class->GetVirtualMethods(sizeof(void*))) {
120 add_method_to_array(&method);
121 }
122 next_class = next_class->GetSuperClass();
123 } while (!next_class->IsObjectClass());
124 // Skip adding any methods from "Object".
125 }
126 CHECK_EQ(array_index, methods_count);
127
128 // Builds an empty exception array.
129 jobjectArray proxy_class_throws = soa.Env()->NewObjectArray(0 /* length */,
130 java_lang_class,
131 nullptr /* initial element*/);
132 soa.Self()->AssertNoPendingException();
133
134 bool already_exists;
135 mirror::Class* proxy_class =
136 class_linker_->CreateLambdaProxyClass(soa,
137 soa.Env()->NewStringUTF(class_name),
138 proxy_class_interfaces,
139 jclass_loader,
140 proxy_class_methods,
141 proxy_class_throws,
142 /*out*/&already_exists);
143
144 CHECK(!already_exists);
145
146 soa.Self()->AssertNoPendingException();
147 return proxy_class;
148 }
149
150 LambdaProxyTest() {
151 }
152
153 virtual void SetUp() {
154 CommonRuntimeTest::SetUp();
155 }
156
157 virtual void SetUpRuntimeOptions(RuntimeOptions* options ATTRIBUTE_UNUSED) {
158 // Do not have any compiler options because we don't want to run as an AOT
159 // (In particular the lambda proxy class generation isn't currently supported for AOT).
160 this->callbacks_.reset();
161 }
162
163 template <typename THandleScope>
164 Handle<mirror::Class> GenerateProxyClass(THandleScope& hs,
165 const char* name,
166 const std::vector<mirror::Class*>& interfaces)
167 SHARED_REQUIRES(Locks::mutator_lock_) {
168 return hs.NewHandle(GenerateProxyClass(*soa_, jclass_loader_, name, interfaces));
169 }
170
171 protected:
172 ScopedObjectAccess* soa_ = nullptr;
173 jobject jclass_loader_ = nullptr;
174};
175
176// Creates a lambda proxy class and check ClassHelper works correctly.
177TEST_F(LambdaProxyTest, ProxyClassHelper) {
178 // gLogVerbosity.class_linker = true; // Uncomment to enable class linker logging.
179
180 ASSERT_NOT_NULL(Thread::Current());
181
182 ScopedObjectAccess soa(Thread::Current());
183 soa_ = &soa;
184
185 // Must happen after CommonRuntimeTest finishes constructing the runtime.
186 jclass_loader_ = LoadDex(TEST_INTERFACE_ENCLOSING_CLASS_NAME);
187 jobject jclass_loader = jclass_loader_;
188
189 StackHandleScope<4> hs(soa.Self());
190 Handle<mirror::ClassLoader> class_loader(
191 hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
192
193 Handle<mirror::Class> J(hs.NewHandle(
194 class_linker_->FindClass(soa.Self(), MAKE_TEST_INTERFACE_NAME("J"), class_loader)));
195 ASSERT_TRUE(J.Get() != nullptr);
196
197 std::vector<mirror::Class*> interfaces;
198 interfaces.push_back(J.Get());
199 Handle<mirror::Class> proxy_class(hs.NewHandle(
200 GenerateProxyClass(soa, jclass_loader, "$Proxy1234", interfaces)));
201 interfaces.clear(); // Don't least possibly stale objects in the array as good practice.
202 ASSERT_TRUE(proxy_class.Get() != nullptr);
203 ASSERT_TRUE(proxy_class->IsLambdaProxyClass());
204 ASSERT_TRUE(proxy_class->IsInitialized());
205
206 EXPECT_EQ(1U, proxy_class->NumDirectInterfaces()); // LambdaInterfaces$J.
207 EXPECT_EQ(J.Get(), mirror::Class::GetDirectInterface(soa.Self(), proxy_class, 0));
208 std::string temp;
209 const char* proxy_class_descriptor = proxy_class->GetDescriptor(&temp);
210 EXPECT_STREQ("L$Proxy1234;", proxy_class_descriptor);
211 EXPECT_EQ(nullptr, proxy_class->GetSourceFile());
212
213 // Make sure all the virtual methods are marked as a proxy
214 for (ArtMethod& method : proxy_class->GetVirtualMethods(sizeof(void*))) {
215 SCOPED_TRACE(PrettyMethod(&method, /* with_signature */true));
216 EXPECT_TRUE(method.IsProxyMethod());
217 EXPECT_TRUE(method.IsLambdaProxyMethod());
218 EXPECT_FALSE(method.IsReflectProxyMethod());
219 }
220}
221
222// Creates a proxy class and check FieldHelper works correctly.
223TEST_F(LambdaProxyTest, ProxyFieldHelper) {
224 // gLogVerbosity.class_linker = true; // Uncomment to enable class linker logging.
225
226 ASSERT_NOT_NULL(Thread::Current());
227
228 ScopedObjectAccess soa(Thread::Current());
229 soa_ = &soa;
230
231 // Must happen after CommonRuntimeTest finishes constructing the runtime.
232 jclass_loader_ = LoadDex(TEST_INTERFACE_ENCLOSING_CLASS_NAME);
233 jobject jclass_loader = jclass_loader_;
234
235 StackHandleScope<9> hs(soa.Self());
236 Handle<mirror::ClassLoader> class_loader(
237 hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
238
239 Handle<mirror::Class> I(hs.NewHandle(
240 class_linker_->FindClass(soa.Self(), MAKE_TEST_INTERFACE_NAME("I"), class_loader)));
241 ASSERT_NOT_NULL(I.Get());
242
243 // Create the lambda proxy which implements interfaces "I".
244 Handle<mirror::Class> proxy_class = GenerateProxyClass(hs,
245 "$Proxy1234",
246 { I.Get() }); // Interfaces.
247
248 ASSERT_NOT_NULL(proxy_class.Get());
249 EXPECT_TRUE(proxy_class->IsLambdaProxyClass());
250 EXPECT_TRUE(proxy_class->IsInitialized());
251 EXPECT_NULL(proxy_class->GetIFieldsPtr());
252
253 LengthPrefixedArray<ArtField>* static_fields = proxy_class->GetSFieldsPtr();
254 ASSERT_NOT_NULL(static_fields);
255
256 // Must have "throws" and "interfaces" static fields.
257 ASSERT_EQ(+mirror::LambdaProxy::kStaticFieldCount, proxy_class->NumStaticFields());
258
259 static constexpr const char* kInterfacesClassName = "[Ljava/lang/Class;";
260 static constexpr const char* kThrowsClassName = "[[Ljava/lang/Class;";
261
262 // Class for "interfaces" field.
263 Handle<mirror::Class> interfaces_field_class =
264 hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), kInterfacesClassName));
265 ASSERT_NOT_NULL(interfaces_field_class.Get());
266
267 // Class for "throws" field.
268 Handle<mirror::Class> throws_field_class =
269 hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), kThrowsClassName));
270 ASSERT_NOT_NULL(throws_field_class.Get());
271
272 // Helper to test the static fields for correctness.
273 auto test_static_field = [&](size_t index,
274 const char* field_name,
275 Handle<mirror::Class>& handle_class,
276 const char* class_name)
277 SHARED_REQUIRES(Locks::mutator_lock_) {
278 ArtField* field = &static_fields->At(index);
279 EXPECT_STREQ(field_name, field->GetName());
280 EXPECT_STREQ(class_name, field->GetTypeDescriptor());
281 EXPECT_EQ(handle_class.Get(), field->GetType</*kResolve*/true>())
282 << "Expected: " << PrettyClass(interfaces_field_class.Get()) << ", "
283 << "Actual: " << PrettyClass(field->GetType</*kResolve*/true>()) << ", "
284 << "field_name: " << field_name;
285 std::string temp;
286 EXPECT_STREQ("L$Proxy1234;", field->GetDeclaringClass()->GetDescriptor(&temp));
287 EXPECT_FALSE(field->IsPrimitiveType());
288 };
289
290 // Test "Class[] interfaces" field.
291 test_static_field(mirror::LambdaProxy::kStaticFieldIndexInterfaces,
292 "interfaces",
293 interfaces_field_class,
294 kInterfacesClassName);
295
296 // Test "Class[][] throws" field.
297 test_static_field(mirror::LambdaProxy::kStaticFieldIndexThrows,
298 "throws",
299 throws_field_class,
300 kThrowsClassName);
301}
302
303// Creates two proxy classes and check the art/mirror fields of their static fields.
304TEST_F(LambdaProxyTest, CheckArtMirrorFieldsOfProxyStaticFields) {
305 // gLogVerbosity.class_linker = true; // Uncomment to enable class linker logging.
306
307 ASSERT_NOT_NULL(Thread::Current());
308
309 ScopedObjectAccess soa(Thread::Current());
310 soa_ = &soa;
311
312 // Must happen after CommonRuntimeTest finishes constructing the runtime.
313 jclass_loader_ = LoadDex(TEST_INTERFACE_ENCLOSING_CLASS_NAME);
314 jobject jclass_loader = jclass_loader_;
315
316 StackHandleScope<8> hs(soa.Self());
317 Handle<mirror::ClassLoader> class_loader(
318 hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
319
320 Handle<mirror::Class> proxyClass0;
321 Handle<mirror::Class> proxyClass1;
322 {
323 Handle<mirror::Class> L(hs.NewHandle(
324 class_linker_->FindClass(soa.Self(), MAKE_TEST_INTERFACE_NAME("L"), class_loader)));
325 ASSERT_TRUE(L.Get() != nullptr);
326
327 std::vector<mirror::Class*> interfaces = { L.Get() };
328 proxyClass0 = hs.NewHandle(GenerateProxyClass(soa, jclass_loader, "$Proxy0", interfaces));
329 proxyClass1 = hs.NewHandle(GenerateProxyClass(soa, jclass_loader, "$Proxy1", interfaces));
330 }
331
332 ASSERT_TRUE(proxyClass0.Get() != nullptr);
333 ASSERT_TRUE(proxyClass0->IsLambdaProxyClass());
334 ASSERT_TRUE(proxyClass0->IsInitialized());
335 ASSERT_TRUE(proxyClass1.Get() != nullptr);
336 ASSERT_TRUE(proxyClass1->IsLambdaProxyClass());
337 ASSERT_TRUE(proxyClass1->IsInitialized());
338
339 LengthPrefixedArray<ArtField>* static_fields0 = proxyClass0->GetSFieldsPtr();
340 ASSERT_TRUE(static_fields0 != nullptr);
341 ASSERT_EQ(2u, static_fields0->size());
342 LengthPrefixedArray<ArtField>* static_fields1 = proxyClass1->GetSFieldsPtr();
343 ASSERT_TRUE(static_fields1 != nullptr);
344 ASSERT_EQ(2u, static_fields1->size());
345
346 EXPECT_EQ(static_fields0->At(0).GetDeclaringClass(), proxyClass0.Get());
347 EXPECT_EQ(static_fields0->At(1).GetDeclaringClass(), proxyClass0.Get());
348 EXPECT_EQ(static_fields1->At(0).GetDeclaringClass(), proxyClass1.Get());
349 EXPECT_EQ(static_fields1->At(1).GetDeclaringClass(), proxyClass1.Get());
350
351 Handle<mirror::Field> field00 =
352 hs.NewHandle(mirror::Field::CreateFromArtField(soa.Self(), &static_fields0->At(0), true));
353 Handle<mirror::Field> field01 =
354 hs.NewHandle(mirror::Field::CreateFromArtField(soa.Self(), &static_fields0->At(1), true));
355 Handle<mirror::Field> field10 =
356 hs.NewHandle(mirror::Field::CreateFromArtField(soa.Self(), &static_fields1->At(0), true));
357 Handle<mirror::Field> field11 =
358 hs.NewHandle(mirror::Field::CreateFromArtField(soa.Self(), &static_fields1->At(1), true));
359 EXPECT_EQ(field00->GetArtField(), &static_fields0->At(0));
360 EXPECT_EQ(field01->GetArtField(), &static_fields0->At(1));
361 EXPECT_EQ(field10->GetArtField(), &static_fields1->At(0));
362 EXPECT_EQ(field11->GetArtField(), &static_fields1->At(1));
363}
364
365// TODO: make sure there's a non-abstract implementation of the single-abstract-method on the class.
366
367} // namespace art