blob: 08960b13d77d070f680440cb46a8918d2f75fcd8 [file] [log] [blame]
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -07001/*
2 * Copyright (C) 2008 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_internal.h"
18#include "class_linker.h"
19#include "object.h"
20
21#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
22
23namespace art {
24
25namespace {
26
27
28// Recursively create an array with multiple dimensions. Elements may be
29// Objects or primitive types.
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -070030Array* CreateMultiArray(Class* array_class, int current_dimension, IntArray* dimensions) {
31 int32_t array_length = dimensions->Get(current_dimension++);
Brian Carlstrom40381fb2011-10-19 14:13:40 -070032 SirtRef<Array> new_array(Array::Alloc(array_class, array_length));
33 if (new_array.get() == NULL) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -070034 CHECK(Thread::Current()->IsExceptionPending());
35 return NULL;
36 }
37 if (current_dimension == dimensions->GetLength()) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -070038 return new_array.get();
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -070039 }
40
41 if (!array_class->GetComponentType()->IsArrayClass()) {
42 // TODO: throw an exception, not relying on class_linker->FindClass to throw.
43 // old code assumed this but if you recurse from "[Foo" to "Foo" to "oo",
44 // you shouldn't assume there isn't a class "oo".
45 }
46 std::string sub_array_descriptor(array_class->GetDescriptor()->ToModifiedUtf8(), 1);
47 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
48 Class* sub_array_class = class_linker->FindClass(sub_array_descriptor,
49 array_class->GetClassLoader());
50 if (sub_array_class == NULL) {
51 CHECK(Thread::Current()->IsExceptionPending());
52 return NULL;
53 }
54 DCHECK(sub_array_class->IsArrayClass());
55 // Create a new sub-array in every element of the array.
Brian Carlstrom40381fb2011-10-19 14:13:40 -070056 SirtRef<ObjectArray<Array> > object_array(new_array->AsObjectArray<Array>());
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -070057 for (int32_t i = 0; i < array_length; i++) {
Brian Carlstrom40381fb2011-10-19 14:13:40 -070058 SirtRef<Array> sub_array(CreateMultiArray(sub_array_class, current_dimension, dimensions));
59 if (sub_array.get() == NULL) {
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -070060 CHECK(Thread::Current()->IsExceptionPending());
61 return NULL;
62 }
Brian Carlstrom40381fb2011-10-19 14:13:40 -070063 object_array->Set(i, sub_array.get());
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -070064 }
Brian Carlstrom40381fb2011-10-19 14:13:40 -070065 return new_array.get();
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -070066}
67
68// Create a multi-dimensional array of Objects or primitive types.
69//
70// We have to generate the names for X[], X[][], X[][][], and so on. The
71// easiest way to deal with that is to create the full name once and then
72// subtract pieces off. Besides, we want to start with the outermost
73// piece and work our way in.
74jobject Array_createMultiArray(JNIEnv* env, jclass, jclass javaElementClass, jobject javaDimArray) {
Brian Carlstromb82b6872011-10-26 17:18:07 -070075 ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -070076 DCHECK(javaElementClass != NULL);
77 Class* element_class = Decode<Class*>(env, javaElementClass);
78 DCHECK(element_class->IsClass());
79 DCHECK(javaDimArray != NULL);
80 Object* dimensions_obj = Decode<Class*>(env, javaDimArray);
81 DCHECK(dimensions_obj->IsArrayInstance());
82 DCHECK(dimensions_obj->GetClass()->GetDescriptor()->Equals("[I"));
83 IntArray* dimensions_array = down_cast<IntArray*>(dimensions_obj);
84
85 // Verify dimensions.
86 //
87 // The caller is responsible for verifying that "dimArray" is non-null
88 // and has a length > 0 and <= 255.
89 int num_dimensions = dimensions_array->GetLength();
90 DCHECK_GT(num_dimensions, 0);
91 DCHECK_LE(num_dimensions, 255);
92
93 for (int i = 0; i < num_dimensions; i++) {
Elliott Hughes6271c422011-10-11 15:43:35 -070094 int dimension = dimensions_array->Get(i);
95 if (dimension < 0) {
96 Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;",
97 "Dimension %d: %d", i, dimension);
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -070098 return NULL;
99 }
100 }
101
102 // Generate the full name of the array class.
103 std::string descriptor(num_dimensions, '[');
104 descriptor += element_class->GetDescriptor()->ToModifiedUtf8();
105
106 // Find/generate the array class.
107 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
108 Class* array_class = class_linker->FindClass(descriptor, element_class->GetClassLoader());
109 if (array_class == NULL) {
110 CHECK(Thread::Current()->IsExceptionPending());
111 return NULL;
112 }
113 // create the array
114 Array* new_array = CreateMultiArray(array_class, 0, dimensions_array);
115 if (new_array == NULL) {
116 CHECK(Thread::Current()->IsExceptionPending());
117 return NULL;
118 }
119 return AddLocalReference<jobject>(env, new_array);
120}
121
122jobject Array_createObjectArray(JNIEnv* env, jclass, jclass javaElementClass, jint length)
123{
Brian Carlstromb82b6872011-10-26 17:18:07 -0700124 ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -0700125 DCHECK(javaElementClass != NULL);
126 Class* element_class = Decode<Class*>(env, javaElementClass);
127 if (length < 0) {
Elliott Hughes6271c422011-10-11 15:43:35 -0700128 Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", length);
Brian Carlstrom5b8e4c82011-09-18 01:38:59 -0700129 return NULL;
130 }
131 std::string descriptor;
132 descriptor += '[';
133 descriptor += element_class->GetDescriptor()->ToModifiedUtf8();
134
135 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
136 Class* array_class = class_linker->FindClass(descriptor, element_class->GetClassLoader());
137 if (array_class == NULL) {
138 CHECK(Thread::Current()->IsExceptionPending());
139 return NULL;
140 }
141 DCHECK(array_class->IsArrayClass());
142 Array* new_array = Array::Alloc(array_class, length);
143 if (new_array == NULL) {
144 CHECK(Thread::Current()->IsExceptionPending());
145 return NULL;
146 }
147 return AddLocalReference<jobject>(env, new_array);
148}
149
150static JNINativeMethod gMethods[] = {
151 NATIVE_METHOD(Array, createMultiArray, "(Ljava/lang/Class;[I)Ljava/lang/Object;"),
152 NATIVE_METHOD(Array, createObjectArray, "(Ljava/lang/Class;I)Ljava/lang/Object;"),
153};
154
155} // namespace
156
157void register_java_lang_reflect_Array(JNIEnv* env) {
158 jniRegisterNativeMethods(env, "java/lang/reflect/Array", gMethods, NELEM(gMethods));
159}
160
161} // namespace art