1/*
2 * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#include "ArrayTypeImpl.h"
27#include "util.h"
28#include "inStream.h"
29#include "outStream.h"
30
31/*
32 * Determine the component class by looking thru all classes for
33 * one that has the signature of the component and the same class loadeer
34 * as the array.  See JVM spec 5.3.3:
35 *     If the component type is a reference type, C is marked as having
36 *     been defined by the defining class loader of the component type.
37 */
38static jdwpError
39getComponentClass(JNIEnv *env, jclass arrayClass, char *componentSignature,
40                jclass *componentClassPtr)
41{
42    jobject arrayClassLoader;
43    jclass *classes;
44    jint count;
45    jclass componentClass = NULL;
46    jdwpError serror;
47    jvmtiError error;
48
49    serror = JDWP_ERROR(NONE);
50
51    error = classLoader(arrayClass, &arrayClassLoader);
52    if (error != JVMTI_ERROR_NONE) {
53        return map2jdwpError(error);
54    }
55
56    error = allLoadedClasses(&classes, &count);
57    if (error != JVMTI_ERROR_NONE) {
58        serror = map2jdwpError(error);
59    } else {
60        int i;
61        for (i = 0; (i < count) && (componentClass == NULL); i++) {
62            char *signature = NULL;
63            jclass clazz = classes[i];
64            jboolean match;
65            jvmtiError error;
66
67            /* signature must match */
68            error = classSignature(clazz, &signature, NULL);
69            if (error != JVMTI_ERROR_NONE) {
70                serror = map2jdwpError(error);
71                break;
72            }
73            match = strcmp(signature, componentSignature) == 0;
74            jvmtiDeallocate(signature);
75
76            /* if signature matches, get class loader to check if
77             * it matches
78             */
79            if (match) {
80                jobject loader;
81                error = classLoader(clazz, &loader);
82                if (error != JVMTI_ERROR_NONE) {
83                    return map2jdwpError(error);
84                }
85                match = isSameObject(env, loader, arrayClassLoader);
86            }
87
88            if (match) {
89                componentClass = clazz;
90            }
91        }
92        jvmtiDeallocate(classes);
93
94        *componentClassPtr = componentClass;
95    }
96
97    if (serror == JDWP_ERROR(NONE) && componentClass == NULL) {
98        /* per JVM spec, component class is always loaded
99         * before array class, so this should never occur.
100         */
101        serror = JDWP_ERROR(NOT_FOUND);
102    }
103
104    return serror;
105}
106
107static void
108writeNewObjectArray(JNIEnv *env, PacketOutputStream *out,
109                 jclass arrayClass, jint size, char *componentSignature)
110{
111
112    WITH_LOCAL_REFS(env, 1) {
113
114        jarray array;
115        jclass componentClass = NULL;
116        jdwpError serror;
117
118        serror = getComponentClass(env, arrayClass,
119                                       componentSignature, &componentClass);
120        if (serror != JDWP_ERROR(NONE)) {
121            outStream_setError(out, serror);
122        } else {
123
124            array = JNI_FUNC_PTR(env,NewObjectArray)(env, size, componentClass, 0);
125            if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
126                JNI_FUNC_PTR(env,ExceptionClear)(env);
127                array = NULL;
128            }
129
130            if (array == NULL) {
131                outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
132            } else {
133                (void)outStream_writeByte(out, specificTypeKey(env, array));
134                (void)outStream_writeObjectRef(env, out, array);
135            }
136
137        }
138
139    } END_WITH_LOCAL_REFS(env);
140}
141
142static void
143writeNewPrimitiveArray(JNIEnv *env, PacketOutputStream *out,
144                       jclass arrayClass, jint size, char *componentSignature)
145{
146
147    WITH_LOCAL_REFS(env, 1) {
148
149        jarray array = NULL;
150
151        switch (componentSignature[0]) {
152            case JDWP_TAG(BYTE):
153                array = JNI_FUNC_PTR(env,NewByteArray)(env, size);
154                break;
155
156            case JDWP_TAG(CHAR):
157                array = JNI_FUNC_PTR(env,NewCharArray)(env, size);
158                break;
159
160            case JDWP_TAG(FLOAT):
161                array = JNI_FUNC_PTR(env,NewFloatArray)(env, size);
162                break;
163
164            case JDWP_TAG(DOUBLE):
165                array = JNI_FUNC_PTR(env,NewDoubleArray)(env, size);
166                break;
167
168            case JDWP_TAG(INT):
169                array = JNI_FUNC_PTR(env,NewIntArray)(env, size);
170                break;
171
172            case JDWP_TAG(LONG):
173                array = JNI_FUNC_PTR(env,NewLongArray)(env, size);
174                break;
175
176            case JDWP_TAG(SHORT):
177                array = JNI_FUNC_PTR(env,NewShortArray)(env, size);
178                break;
179
180            case JDWP_TAG(BOOLEAN):
181                array = JNI_FUNC_PTR(env,NewBooleanArray)(env, size);
182                break;
183
184            default:
185                outStream_setError(out, JDWP_ERROR(TYPE_MISMATCH));
186                break;
187        }
188
189        if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
190            JNI_FUNC_PTR(env,ExceptionClear)(env);
191            array = NULL;
192        }
193
194        if (array == NULL) {
195            outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
196        } else {
197            (void)outStream_writeByte(out, specificTypeKey(env, array));
198            (void)outStream_writeObjectRef(env, out, array);
199        }
200
201    } END_WITH_LOCAL_REFS(env);
202}
203
204static jboolean
205newInstance(PacketInputStream *in, PacketOutputStream *out)
206{
207    JNIEnv *env;
208    char *signature = NULL;
209    char *componentSignature;
210    jclass arrayClass;
211    jint size;
212    jvmtiError error;
213
214    env = getEnv();
215
216    arrayClass = inStream_readClassRef(env, in);
217    if (inStream_error(in)) {
218        return JNI_TRUE;
219    }
220    size = inStream_readInt(in);
221    if (inStream_error(in)) {
222        return JNI_TRUE;
223    }
224
225    error = classSignature(arrayClass, &signature, NULL);
226    if ( error != JVMTI_ERROR_NONE ) {
227        outStream_setError(out, map2jdwpError(error));
228        return JNI_FALSE;
229    }
230    componentSignature = &signature[1];
231
232    if ((componentSignature[0] == JDWP_TAG(OBJECT)) ||
233        (componentSignature[0] == JDWP_TAG(ARRAY))) {
234        writeNewObjectArray(env, out, arrayClass, size, componentSignature);
235    } else {
236        writeNewPrimitiveArray(env, out, arrayClass, size, componentSignature);
237    }
238
239    jvmtiDeallocate(signature);
240    return JNI_TRUE;
241}
242
243void *ArrayType_Cmds[] = { (void *)0x1
244                          ,(void *)newInstance};
245