1*1449Stomee /*
2*1449Stomee  * CDDL HEADER START
3*1449Stomee  *
4*1449Stomee  * The contents of this file are subject to the terms of the
5*1449Stomee  * Common Development and Distribution License (the "License").
6*1449Stomee  * You may not use this file except in compliance with the License.
7*1449Stomee  *
8*1449Stomee  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1449Stomee  * or http://www.opensolaris.org/os/licensing.
10*1449Stomee  * See the License for the specific language governing permissions
11*1449Stomee  * and limitations under the License.
12*1449Stomee  *
13*1449Stomee  * When distributing Covered Code, include this CDDL HEADER in each
14*1449Stomee  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1449Stomee  * If applicable, add the following below this CDDL HEADER, with the
16*1449Stomee  * fields enclosed by brackets "[]" replaced with your own identifying
17*1449Stomee  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1449Stomee  *
19*1449Stomee  * CDDL HEADER END
20*1449Stomee  */
21*1449Stomee 
22*1449Stomee /*
23*1449Stomee  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*1449Stomee  * Use is subject to license terms.
25*1449Stomee  */
26*1449Stomee 
27*1449Stomee #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1449Stomee 
29*1449Stomee #include <stdlib.h>
30*1449Stomee #include <stddef.h>
31*1449Stomee #include <sys/types.h>
32*1449Stomee #include <pthread.h>
33*1449Stomee #include <string.h>
34*1449Stomee #include <dtj_util.h>
35*1449Stomee 
36*1449Stomee /*
37*1449Stomee  * dtj_util.c separates functionality that is generally useful from
38*1449Stomee  * that which is specific to the Java DTrace API.  If moved to a separate
39*1449Stomee  * library, this functionality could be shared by other JNI wrappers.
40*1449Stomee  */
41*1449Stomee 
42*1449Stomee boolean_t g_dtj_util_debug = B_FALSE;
43*1449Stomee static boolean_t g_dtj_load_common = B_FALSE;
44*1449Stomee 
45*1449Stomee /* NativeException */
46*1449Stomee jclass g_nx_jc = 0;
47*1449Stomee jmethodID g_nxinit_jm = 0;
48*1449Stomee 
49*1449Stomee /* java.io.Serializable */
50*1449Stomee jclass g_serial_jc = 0;
51*1449Stomee 
52*1449Stomee /* java.lang.Number */
53*1449Stomee jclass g_number_jc = 0;
54*1449Stomee jmethodID g_shortval_jm = 0;
55*1449Stomee jmethodID g_intval_jm = 0;
56*1449Stomee jmethodID g_longval_jm = 0;
57*1449Stomee 
58*1449Stomee /* java.lang.Byte */
59*1449Stomee jclass g_byte_jc = 0;
60*1449Stomee jmethodID g_byteinit_jm = 0;
61*1449Stomee 
62*1449Stomee /* java.lang.Character */
63*1449Stomee jclass g_char_jc = 0;
64*1449Stomee jmethodID g_charinit_jm = 0;
65*1449Stomee jmethodID g_charval_jm = 0;
66*1449Stomee 
67*1449Stomee /* java.lang.Short */
68*1449Stomee jclass g_short_jc = 0;
69*1449Stomee jmethodID g_shortinit_jm = 0;
70*1449Stomee 
71*1449Stomee /* java.lang.Integer */
72*1449Stomee jclass g_int_jc = 0;
73*1449Stomee jmethodID g_intinit_jm = 0;
74*1449Stomee 
75*1449Stomee /* java.lang.Long */
76*1449Stomee jclass g_long_jc = 0;
77*1449Stomee jmethodID g_longinit_jm = 0;
78*1449Stomee 
79*1449Stomee /* java.lang.String */
80*1449Stomee jclass g_string_jc = 0;
81*1449Stomee jmethodID g_strinit_bytes_jm = 0;
82*1449Stomee jmethodID g_strbytes_jm = 0;
83*1449Stomee jmethodID g_trim_jm = 0;
84*1449Stomee 
85*1449Stomee /* java.lang.StringBuffer */
86*1449Stomee jclass g_buf_jc = 0;
87*1449Stomee jmethodID g_bufinit_jm = 0;
88*1449Stomee jmethodID g_buf_append_char_jm = 0;
89*1449Stomee jmethodID g_buf_append_int_jm = 0;
90*1449Stomee jmethodID g_buf_append_long_jm = 0;
91*1449Stomee jmethodID g_buf_append_str_jm = 0;
92*1449Stomee jmethodID g_buf_append_obj_jm = 0;
93*1449Stomee jmethodID g_buflen_jm = 0;
94*1449Stomee jmethodID g_bufsetlen_jm = 0;
95*1449Stomee 
96*1449Stomee /* java.lang.Object */
97*1449Stomee jclass g_object_jc = 0;
98*1449Stomee jmethodID g_tostring_jm = 0;
99*1449Stomee jmethodID g_equals_jm = 0;
100*1449Stomee 
101*1449Stomee /* java.lang.Enum */
102*1449Stomee jclass g_enum_jc = 0;
103*1449Stomee jmethodID g_enumname_jm = 0;
104*1449Stomee 
105*1449Stomee /* List */
106*1449Stomee jclass g_list_jc = 0;
107*1449Stomee jmethodID g_listclear_jm = 0;
108*1449Stomee jmethodID g_listadd_jm = 0;
109*1449Stomee jmethodID g_listget_jm = 0;
110*1449Stomee jmethodID g_listsize_jm = 0;
111*1449Stomee 
112*1449Stomee /* Global list pools */
113*1449Stomee static uu_list_pool_t *g_pointer_pool = NULL;
114*1449Stomee static uu_list_pool_t *g_string_pool = NULL;
115*1449Stomee 
116*1449Stomee static dtj_status_t dtj_get_jni_classes(JNIEnv *, uu_list_t *, uu_list_pool_t *,
117*1449Stomee     uu_list_pool_t *, uu_list_pool_t *, const dtj_table_entry_t *);
118*1449Stomee static dtj_status_t dtj_cache_jni_methods(JNIEnv *, dtj_java_class_t *);
119*1449Stomee static dtj_status_t dtj_cache_jni_fields(JNIEnv *, dtj_java_class_t *);
120*1449Stomee 
121*1449Stomee /* Constructors */
122*1449Stomee static dtj_java_class_t *dtj_java_class_create(JNIEnv *, jclass *, char *,
123*1449Stomee     uu_list_pool_t *, uu_list_pool_t *, uu_list_pool_t *);
124*1449Stomee static dtj_java_method_t *dtj_java_method_create(JNIEnv *, jmethodID *, char *,
125*1449Stomee     char *, uu_list_pool_t *);
126*1449Stomee static dtj_java_method_t *dtj_java_static_method_create(JNIEnv *, jmethodID *,
127*1449Stomee     char *, char *, uu_list_pool_t *);
128*1449Stomee static dtj_java_field_t *dtj_java_field_create(JNIEnv *, jfieldID *, char *,
129*1449Stomee     char *, uu_list_pool_t *);
130*1449Stomee static dtj_java_field_t *dtj_java_static_field_create(JNIEnv *, jfieldID *,
131*1449Stomee     char *, char *, uu_list_pool_t *);
132*1449Stomee 
133*1449Stomee /* Destructors */
134*1449Stomee static void dtj_java_class_destroy(void *, void *);
135*1449Stomee static void dtj_java_method_destroy(void *, void *);
136*1449Stomee static void dtj_java_field_destroy(void *, void *);
137*1449Stomee 
138*1449Stomee /* Comparison functions, uu_compare_fn_t signature */
139*1449Stomee static int dtj_java_class_cmp(const void *, const void *, void *);
140*1449Stomee static int dtj_java_method_cmp(const void *, const void *, void *);
141*1449Stomee static int dtj_java_field_cmp(const void *, const void *, void *);
142*1449Stomee 
143*1449Stomee /* Java Throwable */
144*1449Stomee static void dtj_throw(JNIEnv *, jclass, const char *, va_list *);
145*1449Stomee 
146*1449Stomee /* Support for uu_list_t wrappers */
147*1449Stomee static boolean_t dtj_check_pointer_pool(void);
148*1449Stomee static boolean_t dtj_check_string_pool(void);
149*1449Stomee 
150*1449Stomee dtj_status_t
151*1449Stomee dtj_load_common(JNIEnv *jenv)
152*1449Stomee {
153*1449Stomee 	dtj_status_t status;
154*1449Stomee 
155*1449Stomee 	static const dtj_table_entry_t table[] = {
156*1449Stomee 		/* NativeException */
157*1449Stomee 		{ JCLASS,  &g_nx_jc,
158*1449Stomee 			"org/opensolaris/os/dtrace/NativeException" },
159*1449Stomee 		{ JMETHOD, &g_nxinit_jm, CONSTRUCTOR,
160*1449Stomee 			"(Ljava/lang/String;ILjava/lang/Throwable;)V" },
161*1449Stomee 
162*1449Stomee 		/* java.io.Serializable */
163*1449Stomee 		{ JCLASS,  &g_serial_jc, "java/io/Serializable" },
164*1449Stomee 
165*1449Stomee 		/* java.lang.Number */
166*1449Stomee 		{ JCLASS,  &g_number_jc, "java/lang/Number" },
167*1449Stomee 		{ JMETHOD, &g_shortval_jm, "shortValue", "()S" },
168*1449Stomee 		{ JMETHOD, &g_intval_jm, "intValue", "()I" },
169*1449Stomee 		{ JMETHOD, &g_longval_jm, "longValue", "()J" },
170*1449Stomee 
171*1449Stomee 		/* java.lang.Byte */
172*1449Stomee 		{ JCLASS,  &g_byte_jc, "java/lang/Byte" },
173*1449Stomee 		{ JMETHOD, &g_byteinit_jm, CONSTRUCTOR, "(B)V" },
174*1449Stomee 
175*1449Stomee 		/* java.lang.Character */
176*1449Stomee 		{ JCLASS,  &g_char_jc, "java/lang/Character" },
177*1449Stomee 		{ JMETHOD, &g_charinit_jm, CONSTRUCTOR, "(C)V" },
178*1449Stomee 		{ JMETHOD, &g_charval_jm, "charValue", "()C" },
179*1449Stomee 
180*1449Stomee 		/* java.lang.Short */
181*1449Stomee 		{ JCLASS,  &g_short_jc, "java/lang/Short" },
182*1449Stomee 		{ JMETHOD, &g_shortinit_jm, CONSTRUCTOR, "(S)V" },
183*1449Stomee 
184*1449Stomee 		/* java.lang.Integer */
185*1449Stomee 		{ JCLASS,  &g_int_jc, "java/lang/Integer" },
186*1449Stomee 		{ JMETHOD, &g_intinit_jm, CONSTRUCTOR, "(I)V" },
187*1449Stomee 
188*1449Stomee 		/* java.lang.Long */
189*1449Stomee 		{ JCLASS,  &g_long_jc, "java/lang/Long" },
190*1449Stomee 		{ JMETHOD, &g_longinit_jm, CONSTRUCTOR, "(J)V" },
191*1449Stomee 
192*1449Stomee 		/* java.lang.String */
193*1449Stomee 		{ JCLASS,  &g_string_jc, "java/lang/String" },
194*1449Stomee 		{ JMETHOD, &g_strinit_bytes_jm, CONSTRUCTOR, "([B)V" },
195*1449Stomee 		{ JMETHOD, &g_strbytes_jm, "getBytes", "()[B" },
196*1449Stomee 		{ JMETHOD, &g_trim_jm, "trim", "()Ljava/lang/String;" },
197*1449Stomee 
198*1449Stomee 		/* java.lang.StringBuffer */
199*1449Stomee 		{ JCLASS,  &g_buf_jc, "java/lang/StringBuffer" },
200*1449Stomee 		{ JMETHOD, &g_bufinit_jm, CONSTRUCTOR, "()V" },
201*1449Stomee 		{ JMETHOD, &g_buf_append_char_jm, "append",
202*1449Stomee 			"(C)Ljava/lang/StringBuffer;" },
203*1449Stomee 		{ JMETHOD, &g_buf_append_int_jm, "append",
204*1449Stomee 			"(I)Ljava/lang/StringBuffer;" },
205*1449Stomee 		{ JMETHOD, &g_buf_append_long_jm, "append",
206*1449Stomee 			"(J)Ljava/lang/StringBuffer;" },
207*1449Stomee 		{ JMETHOD, &g_buf_append_str_jm, "append",
208*1449Stomee 			"(Ljava/lang/String;)Ljava/lang/StringBuffer;" },
209*1449Stomee 		{ JMETHOD, &g_buf_append_obj_jm, "append",
210*1449Stomee 			"(Ljava/lang/Object;)Ljava/lang/StringBuffer;" },
211*1449Stomee 		{ JMETHOD, &g_buflen_jm, "length", "()I" },
212*1449Stomee 		{ JMETHOD, &g_bufsetlen_jm, "setLength", "(I)V" },
213*1449Stomee 
214*1449Stomee 		/* java.lang.Object */
215*1449Stomee 		{ JCLASS,  &g_object_jc, "java/lang/Object" },
216*1449Stomee 		{ JMETHOD, &g_tostring_jm, "toString",
217*1449Stomee 			"()Ljava/lang/String;" },
218*1449Stomee 		{ JMETHOD, &g_equals_jm, "equals",
219*1449Stomee 			"(Ljava/lang/Object;)Z" },
220*1449Stomee 
221*1449Stomee 		/* java.lang.Enum */
222*1449Stomee 		{ JCLASS,  &g_enum_jc, "java/lang/Enum" },
223*1449Stomee 		{ JMETHOD, &g_enumname_jm, "name",
224*1449Stomee 			"()Ljava/lang/String;" },
225*1449Stomee 
226*1449Stomee 		/* List */
227*1449Stomee 		{ JCLASS, &g_list_jc, "java/util/List" },
228*1449Stomee 		{ JMETHOD, &g_listclear_jm, "clear", "()V" },
229*1449Stomee 		{ JMETHOD, &g_listadd_jm, "add", "(Ljava/lang/Object;)Z" },
230*1449Stomee 		{ JMETHOD, &g_listget_jm, "get", "(I)Ljava/lang/Object;" },
231*1449Stomee 		{ JMETHOD, &g_listsize_jm, "size", "()I" },
232*1449Stomee 
233*1449Stomee 		{ DTJ_TYPE_END }
234*1449Stomee 	};
235*1449Stomee 
236*1449Stomee 	status = dtj_cache_jni_classes(jenv, table);
237*1449Stomee 	if (status == DTJ_OK) {
238*1449Stomee 		g_dtj_load_common = B_TRUE;
239*1449Stomee 	}
240*1449Stomee 	return (status);
241*1449Stomee }
242*1449Stomee 
243*1449Stomee static int
244*1449Stomee /* ARGSUSED */
245*1449Stomee dtj_java_class_cmp(const void * v1, const void * v2, void *arg)
246*1449Stomee {
247*1449Stomee 	const dtj_java_class_t *c1 = v1;
248*1449Stomee 	const dtj_java_class_t *c2 = v2;
249*1449Stomee 	return (strcmp(c1->djc_name, c2->djc_name));
250*1449Stomee }
251*1449Stomee 
252*1449Stomee static int
253*1449Stomee /* ARGSUSED */
254*1449Stomee dtj_java_method_cmp(const void *v1, const void *v2, void *arg)
255*1449Stomee {
256*1449Stomee 	int cmp;
257*1449Stomee 	const dtj_java_method_t *m1 = v1;
258*1449Stomee 	const dtj_java_method_t *m2 = v2;
259*1449Stomee 	cmp = strcmp(m1->djm_name, m2->djm_name);
260*1449Stomee 	if (cmp == 0) {
261*1449Stomee 		cmp = strcmp(m1->djm_signature, m2->djm_signature);
262*1449Stomee 	}
263*1449Stomee 	return (cmp);
264*1449Stomee }
265*1449Stomee 
266*1449Stomee static int
267*1449Stomee /* ARGSUSED */
268*1449Stomee dtj_java_field_cmp(const void *v1, const void *v2, void *arg)
269*1449Stomee {
270*1449Stomee 	const dtj_java_field_t *f1 = v1;
271*1449Stomee 	const dtj_java_field_t *f2 = v2;
272*1449Stomee 	return (strcmp(f1->djf_name, f2->djf_name));
273*1449Stomee }
274*1449Stomee 
275*1449Stomee static dtj_java_class_t *
276*1449Stomee dtj_java_class_create(JNIEnv *jenv, jclass *jc, char *name,
277*1449Stomee     uu_list_pool_t *classpool, uu_list_pool_t *methodpool,
278*1449Stomee     uu_list_pool_t *fieldpool)
279*1449Stomee {
280*1449Stomee 	dtj_java_class_t *c = uu_zalloc(sizeof (dtj_java_class_t));
281*1449Stomee 	if (c) {
282*1449Stomee 		uu_list_node_init(c, &c->djc_node, classpool);
283*1449Stomee 		c->djc_ptr = jc;
284*1449Stomee 		c->djc_name = name;
285*1449Stomee 		c->djc_methods = uu_list_create(methodpool, NULL,
286*1449Stomee 		    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
287*1449Stomee 		if (!c->djc_methods) {
288*1449Stomee 			dtj_throw_out_of_memory(jenv,
289*1449Stomee 			    "Failed method list creation");
290*1449Stomee 			uu_list_node_fini(c, &c->djc_node, classpool);
291*1449Stomee 			free(c);
292*1449Stomee 			c = NULL;
293*1449Stomee 		}
294*1449Stomee 		c->djc_fields = uu_list_create(fieldpool, NULL,
295*1449Stomee 		    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
296*1449Stomee 		if (!c->djc_fields) {
297*1449Stomee 			dtj_throw_out_of_memory(jenv,
298*1449Stomee 			    "Failed field list creation");
299*1449Stomee 			uu_list_destroy(c->djc_methods);
300*1449Stomee 			c->djc_methods = NULL;
301*1449Stomee 			uu_list_node_fini(c, &c->djc_node, classpool);
302*1449Stomee 			free(c);
303*1449Stomee 			c = NULL;
304*1449Stomee 		}
305*1449Stomee 	} else {
306*1449Stomee 		dtj_throw_out_of_memory(jenv,
307*1449Stomee 		    "Failed to allocate class description");
308*1449Stomee 	}
309*1449Stomee 	return (c);
310*1449Stomee }
311*1449Stomee 
312*1449Stomee static dtj_java_method_t *
313*1449Stomee dtj_java_method_create(JNIEnv *jenv, jmethodID *jm, char *name, char *signature,
314*1449Stomee     uu_list_pool_t *methodpool)
315*1449Stomee {
316*1449Stomee 	dtj_java_method_t *m = uu_zalloc(sizeof (dtj_java_method_t));
317*1449Stomee 	if (m) {
318*1449Stomee 		uu_list_node_init(m, &m->djm_node, methodpool);
319*1449Stomee 		m->djm_ptr = jm;
320*1449Stomee 		m->djm_name = name;
321*1449Stomee 		m->djm_signature = signature;
322*1449Stomee 		m->djm_static = B_FALSE;
323*1449Stomee 	} else {
324*1449Stomee 		dtj_throw_out_of_memory(jenv,
325*1449Stomee 		    "Failed to allocate method description");
326*1449Stomee 	}
327*1449Stomee 	return (m);
328*1449Stomee }
329*1449Stomee 
330*1449Stomee static dtj_java_method_t *
331*1449Stomee dtj_java_static_method_create(JNIEnv *jenv, jmethodID *jm, char *name,
332*1449Stomee     char *signature, uu_list_pool_t *methodpool)
333*1449Stomee {
334*1449Stomee 	dtj_java_method_t *m = dtj_java_method_create(jenv, jm, name, signature,
335*1449Stomee 	    methodpool);
336*1449Stomee 	if (m) {
337*1449Stomee 		m->djm_static = B_TRUE;
338*1449Stomee 	}
339*1449Stomee 	return (m);
340*1449Stomee }
341*1449Stomee 
342*1449Stomee static dtj_java_field_t *
343*1449Stomee dtj_java_field_create(JNIEnv *jenv, jfieldID *jf, char *name, char *type,
344*1449Stomee     uu_list_pool_t *fieldpool)
345*1449Stomee {
346*1449Stomee 	dtj_java_field_t *f = uu_zalloc(sizeof (dtj_java_field_t));
347*1449Stomee 	if (f) {
348*1449Stomee 		uu_list_node_init(f, &f->djf_node, fieldpool);
349*1449Stomee 		f->djf_ptr = jf;
350*1449Stomee 		f->djf_name = name;
351*1449Stomee 		f->djf_type = type;
352*1449Stomee 		f->djf_static = B_FALSE;
353*1449Stomee 	} else {
354*1449Stomee 		dtj_throw_out_of_memory(jenv,
355*1449Stomee 		    "Failed to allocate field description");
356*1449Stomee 	}
357*1449Stomee 	return (f);
358*1449Stomee }
359*1449Stomee 
360*1449Stomee static dtj_java_field_t *
361*1449Stomee dtj_java_static_field_create(JNIEnv *jenv, jfieldID *jf, char *name, char *type,
362*1449Stomee     uu_list_pool_t *fieldpool)
363*1449Stomee {
364*1449Stomee 	dtj_java_field_t *f = dtj_java_field_create(jenv, jf, name, type,
365*1449Stomee 	    fieldpool);
366*1449Stomee 	if (f) {
367*1449Stomee 		f->djf_static = B_TRUE;
368*1449Stomee 	}
369*1449Stomee 	return (f);
370*1449Stomee }
371*1449Stomee 
372*1449Stomee static void
373*1449Stomee /* ARGSUSED */
374*1449Stomee dtj_java_class_destroy(void *v, void *arg)
375*1449Stomee {
376*1449Stomee 	if (v) {
377*1449Stomee 		dtj_java_class_t *c = v;
378*1449Stomee 		c->djc_ptr = NULL;  /* do not free user-defined storage */
379*1449Stomee 		c->djc_name = NULL; /* string literal */
380*1449Stomee 		dtj_list_destroy(c->djc_methods, dtj_java_method_destroy, NULL);
381*1449Stomee 		dtj_list_destroy(c->djc_fields, dtj_java_field_destroy, NULL);
382*1449Stomee 		c->djc_methods = NULL;
383*1449Stomee 		c->djc_fields = NULL;
384*1449Stomee 		uu_free(v);
385*1449Stomee 	}
386*1449Stomee }
387*1449Stomee 
388*1449Stomee static void
389*1449Stomee /* ARGSUSED */
390*1449Stomee dtj_java_method_destroy(void *v, void *arg)
391*1449Stomee {
392*1449Stomee 	if (v) {
393*1449Stomee 		dtj_java_method_t *m = v;
394*1449Stomee 		m->djm_ptr = NULL;	/* do not free user-defined space */
395*1449Stomee 		m->djm_name = NULL;	/* string literal */
396*1449Stomee 		m->djm_signature = NULL;	/* string literal */
397*1449Stomee 		uu_free(v);
398*1449Stomee 	}
399*1449Stomee }
400*1449Stomee 
401*1449Stomee static void
402*1449Stomee /* ARGSUSED */
403*1449Stomee dtj_java_field_destroy(void *v, void *arg)
404*1449Stomee {
405*1449Stomee 	if (v) {
406*1449Stomee 		dtj_java_field_t *f = v;
407*1449Stomee 		f->djf_ptr = NULL;  /* do not free user-defined space */
408*1449Stomee 		f->djf_name = NULL; /* string literal */
409*1449Stomee 		f->djf_type = NULL; /* string literal */
410*1449Stomee 		uu_free(f);
411*1449Stomee 	}
412*1449Stomee }
413*1449Stomee 
414*1449Stomee dtj_status_t
415*1449Stomee dtj_cache_jni_classes(JNIEnv *jenv, const dtj_table_entry_t *table)
416*1449Stomee {
417*1449Stomee 	dtj_java_class_t *class;
418*1449Stomee 	uu_list_pool_t *classpool;
419*1449Stomee 	uu_list_pool_t *methodpool;
420*1449Stomee 	uu_list_pool_t *fieldpool;
421*1449Stomee 	uu_list_t *classes;
422*1449Stomee 	uu_list_walk_t *itr;
423*1449Stomee 	jclass jc;
424*1449Stomee 	jclass gjc;
425*1449Stomee 	dtj_status_t status;
426*1449Stomee 
427*1449Stomee 	classpool = uu_list_pool_create("classpool",
428*1449Stomee 	    sizeof (dtj_java_class_t),
429*1449Stomee 	    offsetof(dtj_java_class_t, djc_node), dtj_java_class_cmp,
430*1449Stomee 	    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
431*1449Stomee 	if (!classpool) {
432*1449Stomee 		dtj_throw_out_of_memory(jenv, "failed class pool creation");
433*1449Stomee 		return (DTJ_ERR);
434*1449Stomee 	}
435*1449Stomee 	methodpool = uu_list_pool_create("methodpool",
436*1449Stomee 	    sizeof (dtj_java_method_t),
437*1449Stomee 	    offsetof(dtj_java_method_t, djm_node), dtj_java_method_cmp,
438*1449Stomee 	    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
439*1449Stomee 	if (!methodpool) {
440*1449Stomee 		dtj_throw_out_of_memory(jenv, "failed method pool creation");
441*1449Stomee 		return (DTJ_ERR);
442*1449Stomee 	}
443*1449Stomee 	fieldpool = uu_list_pool_create("fieldpool",
444*1449Stomee 	    sizeof (dtj_java_field_t),
445*1449Stomee 	    offsetof(dtj_java_field_t, djf_node), dtj_java_field_cmp,
446*1449Stomee 	    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
447*1449Stomee 	if (!fieldpool) {
448*1449Stomee 		dtj_throw_out_of_memory(jenv, "failed field pool creation");
449*1449Stomee 		return (DTJ_ERR);
450*1449Stomee 	}
451*1449Stomee 
452*1449Stomee 	classes = uu_list_create(classpool, NULL,
453*1449Stomee 	    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
454*1449Stomee 	if (!classes) {
455*1449Stomee 		dtj_throw_out_of_memory(jenv, "failed class list creation");
456*1449Stomee 		return (DTJ_ERR);
457*1449Stomee 	}
458*1449Stomee 
459*1449Stomee 	status = dtj_get_jni_classes(jenv, classes, classpool, methodpool,
460*1449Stomee 	    fieldpool, table);
461*1449Stomee 	if (status != DTJ_OK) {
462*1449Stomee 		/* java error pending */
463*1449Stomee 		return (status);
464*1449Stomee 	}
465*1449Stomee 
466*1449Stomee 	itr = uu_list_walk_start(classes, 0);
467*1449Stomee 	while ((class = uu_list_walk_next(itr)) != NULL) {
468*1449Stomee 		jc = (*jenv)->FindClass(jenv, class->djc_name);
469*1449Stomee 		if (!jc) {
470*1449Stomee 			/* NoClassDefFoundError pending */
471*1449Stomee 			return (DTJ_ERR);
472*1449Stomee 		}
473*1449Stomee 		gjc = (*jenv)->NewGlobalRef(jenv, jc);
474*1449Stomee 		(*jenv)->DeleteLocalRef(jenv, jc);
475*1449Stomee 		if (!gjc) {
476*1449Stomee 			dtj_throw_out_of_memory(jenv,
477*1449Stomee 			    "Failed to create global class reference");
478*1449Stomee 			return (DTJ_ERR);
479*1449Stomee 		}
480*1449Stomee 		*(class->djc_ptr) = gjc;
481*1449Stomee 		status = dtj_cache_jni_methods(jenv, class);
482*1449Stomee 		if (status != DTJ_OK) {
483*1449Stomee 			/* java error pending */
484*1449Stomee 			return (status);
485*1449Stomee 		}
486*1449Stomee 		status = dtj_cache_jni_fields(jenv, class);
487*1449Stomee 		if (status != DTJ_OK) {
488*1449Stomee 			/* java error pending */
489*1449Stomee 			return (status);
490*1449Stomee 		}
491*1449Stomee 	}
492*1449Stomee 	uu_list_walk_end(itr);
493*1449Stomee 	dtj_list_destroy(classes, dtj_java_class_destroy, NULL);
494*1449Stomee 	uu_list_pool_destroy(classpool);
495*1449Stomee 	uu_list_pool_destroy(methodpool);
496*1449Stomee 	uu_list_pool_destroy(fieldpool);
497*1449Stomee 	return (DTJ_OK);
498*1449Stomee }
499*1449Stomee 
500*1449Stomee /*
501*1449Stomee  * Converts JNI table entry desriptions into java_class_t descriptors.
502*1449Stomee  */
503*1449Stomee static dtj_status_t
504*1449Stomee dtj_get_jni_classes(JNIEnv *jenv, uu_list_t *classes,
505*1449Stomee     uu_list_pool_t *classpool, uu_list_pool_t *methodpool,
506*1449Stomee     uu_list_pool_t *fieldpool, const dtj_table_entry_t *table)
507*1449Stomee {
508*1449Stomee 	int i;
509*1449Stomee 	dtj_java_class_t *c = NULL;
510*1449Stomee 	dtj_java_method_t *m;
511*1449Stomee 	dtj_java_field_t *f;
512*1449Stomee 
513*1449Stomee 	for (i = 0; table[i].djte_type != DTJ_TYPE_END; ++i) {
514*1449Stomee 		/*
515*1449Stomee 		 * Class not added until all of its method and field information
516*1449Stomee 		 * is attached, so we defer adding a class until the next
517*1449Stomee 		 * element with type JCLASS.
518*1449Stomee 		 */
519*1449Stomee 		switch (table[i].djte_type) {
520*1449Stomee 		case JCLASS:
521*1449Stomee 			if (c) {
522*1449Stomee 				/* previous class */
523*1449Stomee 				if (!dtj_list_add(classes, c)) {
524*1449Stomee 					dtj_throw_out_of_memory(jenv,
525*1449Stomee 					    "Failed to add class description");
526*1449Stomee 					/*
527*1449Stomee 					 * In response to an error return value,
528*1449Stomee 					 * the caller will delete the class
529*1449Stomee 					 * descriptions list with any
530*1449Stomee 					 * descriptions created so far.
531*1449Stomee 					 */
532*1449Stomee 					return (DTJ_ERR);
533*1449Stomee 				}
534*1449Stomee 			}
535*1449Stomee 			c = dtj_java_class_create(jenv,
536*1449Stomee 			    (jclass *)table[i].djte_addr, table[i].djte_name,
537*1449Stomee 			    classpool, methodpool, fieldpool);
538*1449Stomee 			if (!c) {
539*1449Stomee 				/* OutOfMemoryError pending */
540*1449Stomee 				return (DTJ_ERR);
541*1449Stomee 			}
542*1449Stomee 			break;
543*1449Stomee 		case JMETHOD:
544*1449Stomee 			if (!c) {
545*1449Stomee 				dtj_throw_illegal_state(jenv,
546*1449Stomee 				    "method description not preceded "
547*1449Stomee 				    "by class description");
548*1449Stomee 				return (DTJ_ERR);
549*1449Stomee 			}
550*1449Stomee 			m = dtj_java_method_create(jenv,
551*1449Stomee 			    (jmethodID *)table[i].djte_addr,
552*1449Stomee 			    table[i].djte_name, table[i].djte_desc,
553*1449Stomee 			    methodpool);
554*1449Stomee 			if (!m) {
555*1449Stomee 				/* OutOfMemoryError pending */
556*1449Stomee 				return (DTJ_ERR);
557*1449Stomee 			}
558*1449Stomee 			if (!dtj_list_add(c->djc_methods, m)) {
559*1449Stomee 				dtj_throw_out_of_memory(jenv,
560*1449Stomee 				    "Failed to add method description");
561*1449Stomee 				return (DTJ_ERR);
562*1449Stomee 			}
563*1449Stomee 			break;
564*1449Stomee 		case JMETHOD_STATIC:
565*1449Stomee 			if (!c) {
566*1449Stomee 				dtj_throw_illegal_state(jenv,
567*1449Stomee 				    "static method description not preceded "
568*1449Stomee 				    "by class description");
569*1449Stomee 				return (DTJ_ERR);
570*1449Stomee 			}
571*1449Stomee 			m = dtj_java_static_method_create(jenv,
572*1449Stomee 			    (jmethodID *)table[i].djte_addr,
573*1449Stomee 			    table[i].djte_name, table[i].djte_desc,
574*1449Stomee 			    methodpool);
575*1449Stomee 			if (!m) {
576*1449Stomee 				/* OutOfMemoryError pending */
577*1449Stomee 				return (DTJ_ERR);
578*1449Stomee 			}
579*1449Stomee 			if (!dtj_list_add(c->djc_methods, m)) {
580*1449Stomee 				dtj_throw_out_of_memory(jenv,
581*1449Stomee 				    "Failed to add static method description");
582*1449Stomee 				return (DTJ_ERR);
583*1449Stomee 			}
584*1449Stomee 			break;
585*1449Stomee 		case JFIELD:
586*1449Stomee 			if (!c) {
587*1449Stomee 				dtj_throw_illegal_state(jenv,
588*1449Stomee 				    "field description not preceded "
589*1449Stomee 				    "by class description");
590*1449Stomee 				return (DTJ_ERR);
591*1449Stomee 			}
592*1449Stomee 			f = dtj_java_field_create(jenv,
593*1449Stomee 			    (jfieldID *)table[i].djte_addr,
594*1449Stomee 			    table[i].djte_name, table[i].djte_desc,
595*1449Stomee 			    fieldpool);
596*1449Stomee 			if (!f) {
597*1449Stomee 				/* OutOfMemoryError pending */
598*1449Stomee 				return (DTJ_ERR);
599*1449Stomee 			}
600*1449Stomee 			if (!dtj_list_add(c->djc_fields, f)) {
601*1449Stomee 				dtj_throw_out_of_memory(jenv,
602*1449Stomee 				    "Failed to add field description");
603*1449Stomee 				return (DTJ_ERR);
604*1449Stomee 			}
605*1449Stomee 			break;
606*1449Stomee 		case JFIELD_STATIC:
607*1449Stomee 			if (!c) {
608*1449Stomee 				dtj_throw_illegal_state(jenv,
609*1449Stomee 				    "static field description not preceded "
610*1449Stomee 				    "by class description");
611*1449Stomee 				return (DTJ_ERR);
612*1449Stomee 			}
613*1449Stomee 			f = dtj_java_static_field_create(jenv,
614*1449Stomee 			    (jfieldID *)table[i].djte_addr,
615*1449Stomee 			    table[i].djte_name, table[i].djte_desc,
616*1449Stomee 			    fieldpool);
617*1449Stomee 			if (!f) {
618*1449Stomee 				/* OutOfMemoryError pending */
619*1449Stomee 				return (DTJ_ERR);
620*1449Stomee 			}
621*1449Stomee 			if (!dtj_list_add(c->djc_fields, f)) {
622*1449Stomee 				dtj_throw_out_of_memory(jenv,
623*1449Stomee 				    "Failed to add static field description");
624*1449Stomee 				return (DTJ_ERR);
625*1449Stomee 			}
626*1449Stomee 			break;
627*1449Stomee 		default:
628*1449Stomee 			dtj_throw_illegal_state(jenv,
629*1449Stomee 			    "Unexpected jni_type_e: %d", table[i].djte_type);
630*1449Stomee 			return (DTJ_ERR);
631*1449Stomee 		}
632*1449Stomee 	}
633*1449Stomee 	if (c) {
634*1449Stomee 		/* last class */
635*1449Stomee 		if (!dtj_list_add(classes, c)) {
636*1449Stomee 			dtj_throw_out_of_memory(jenv,
637*1449Stomee 			    "Failed to add class description");
638*1449Stomee 			return (DTJ_ERR);
639*1449Stomee 		}
640*1449Stomee 	}
641*1449Stomee 
642*1449Stomee 	return (DTJ_OK);
643*1449Stomee }
644*1449Stomee 
645*1449Stomee static dtj_status_t
646*1449Stomee dtj_cache_jni_methods(JNIEnv *jenv, dtj_java_class_t *c)
647*1449Stomee {
648*1449Stomee 	dtj_java_method_t *method;
649*1449Stomee 	jmethodID jm;
650*1449Stomee 	uu_list_walk_t *itr;
651*1449Stomee 	itr = uu_list_walk_start(c->djc_methods, 0);
652*1449Stomee 	while ((method = uu_list_walk_next(itr)) != NULL) {
653*1449Stomee 		if (method->djm_static) {
654*1449Stomee 			jm = (*jenv)->GetStaticMethodID(jenv, *(c->djc_ptr),
655*1449Stomee 			    method->djm_name, method->djm_signature);
656*1449Stomee 		} else {
657*1449Stomee 			jm = (*jenv)->GetMethodID(jenv, *(c->djc_ptr),
658*1449Stomee 			    method->djm_name, method->djm_signature);
659*1449Stomee 		}
660*1449Stomee 		if (jm == 0) {
661*1449Stomee 			/*
662*1449Stomee 			 * The pending NoSuchMethodError gives only the
663*1449Stomee 			 * method name, which is not so helpful for
664*1449Stomee 			 * overloaded methods and methods such as <init>
665*1449Stomee 			 * that have the same name in multiple classes.
666*1449Stomee 			 * Clear the pending error and throw one that
667*1449Stomee 			 * includes the class name and the method
668*1449Stomee 			 * signature.
669*1449Stomee 			 */
670*1449Stomee 			jclass jc;
671*1449Stomee 			char msg[DTJ_MSG_SIZE];
672*1449Stomee 			(*jenv)->ExceptionClear(jenv);
673*1449Stomee 			(void) snprintf(msg, sizeof (msg), "%s %s %s",
674*1449Stomee 			    c->djc_name, method->djm_name,
675*1449Stomee 			    method->djm_signature);
676*1449Stomee 
677*1449Stomee 			jc = (*jenv)->FindClass(jenv,
678*1449Stomee 			    "java/lang/NoSuchMethodError");
679*1449Stomee 			(*jenv)->ThrowNew(jenv, jc, msg);
680*1449Stomee 			(*jenv)->DeleteLocalRef(jenv, jc);
681*1449Stomee 			return (DTJ_ERR);
682*1449Stomee 		}
683*1449Stomee 		*(method->djm_ptr) = jm;
684*1449Stomee 	}
685*1449Stomee 	uu_list_walk_end(itr);
686*1449Stomee 	return (DTJ_OK);
687*1449Stomee }
688*1449Stomee 
689*1449Stomee static dtj_status_t
690*1449Stomee dtj_cache_jni_fields(JNIEnv *jenv, dtj_java_class_t *c)
691*1449Stomee {
692*1449Stomee 	dtj_java_field_t *field;
693*1449Stomee 	jfieldID jf;
694*1449Stomee 	uu_list_walk_t *itr;
695*1449Stomee 	itr = uu_list_walk_start(c->djc_fields, 0);
696*1449Stomee 	while ((field = uu_list_walk_next(itr)) != NULL) {
697*1449Stomee 		if (field->djf_static) {
698*1449Stomee 			jf = (*jenv)->GetStaticFieldID(jenv, *(c->djc_ptr),
699*1449Stomee 			    field->djf_name, field->djf_type);
700*1449Stomee 		} else {
701*1449Stomee 			jf = (*jenv)->GetFieldID(jenv, *(c->djc_ptr),
702*1449Stomee 			    field->djf_name, field->djf_type);
703*1449Stomee 		}
704*1449Stomee 		if (jf == 0) {
705*1449Stomee 			jclass jc;
706*1449Stomee 			char msg[DTJ_MSG_SIZE];
707*1449Stomee 			(*jenv)->ExceptionClear(jenv);
708*1449Stomee 			(void) snprintf(msg, sizeof (msg),
709*1449Stomee 			    "%s.%s signature: %s", c->djc_name,
710*1449Stomee 			    field->djf_name, field->djf_type);
711*1449Stomee 
712*1449Stomee 			jc = (*jenv)->FindClass(jenv,
713*1449Stomee 			    "java/lang/NoSuchFieldError");
714*1449Stomee 			(*jenv)->ThrowNew(jenv, jc, msg);
715*1449Stomee 			(*jenv)->DeleteLocalRef(jenv, jc);
716*1449Stomee 			return (DTJ_ERR);
717*1449Stomee 		}
718*1449Stomee 		*(field->djf_ptr) = jf;
719*1449Stomee 	}
720*1449Stomee 	uu_list_walk_end(itr);
721*1449Stomee 	return (DTJ_OK);
722*1449Stomee }
723*1449Stomee 
724*1449Stomee 
725*1449Stomee /* Common utilities */
726*1449Stomee 
727*1449Stomee static void
728*1449Stomee dtj_throw(JNIEnv *jenv, jclass jc, const char *fmt, va_list *ap)
729*1449Stomee {
730*1449Stomee 	char msg[DTJ_MSG_SIZE];
731*1449Stomee 	(void) vsnprintf(msg, sizeof (msg), fmt, *ap);
732*1449Stomee 	(*jenv)->ThrowNew(jenv, jc, msg);
733*1449Stomee }
734*1449Stomee 
735*1449Stomee void
736*1449Stomee dtj_throw_out_of_memory(JNIEnv *jenv, const char *fmt, ...)
737*1449Stomee {
738*1449Stomee 	va_list ap;
739*1449Stomee 	jclass jc;
740*1449Stomee 	/*
741*1449Stomee 	 * JNI documentation unclear whether NewGlobalRef() can throw
742*1449Stomee 	 * OutOfMemoryError, so we'll make this function safe in case
743*1449Stomee 	 * OutOfMemoryError has already been thrown
744*1449Stomee 	 */
745*1449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
746*1449Stomee 		return;
747*1449Stomee 	}
748*1449Stomee 	jc = (*jenv)->FindClass(jenv,
749*1449Stomee 	    "java/lang/OutOfMemoryError");
750*1449Stomee 	va_start(ap, fmt);
751*1449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
752*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
753*1449Stomee 	va_end(ap);
754*1449Stomee }
755*1449Stomee 
756*1449Stomee void
757*1449Stomee dtj_throw_null_pointer(JNIEnv *jenv, const char *fmt, ...)
758*1449Stomee {
759*1449Stomee 	va_list ap;
760*1449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
761*1449Stomee 	    "java/lang/NullPointerException");
762*1449Stomee 	va_start(ap, fmt);
763*1449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
764*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
765*1449Stomee 	va_end(ap);
766*1449Stomee }
767*1449Stomee 
768*1449Stomee void
769*1449Stomee dtj_throw_illegal_state(JNIEnv *jenv, const char *fmt, ...)
770*1449Stomee {
771*1449Stomee 	va_list ap;
772*1449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
773*1449Stomee 	    "java/lang/IllegalStateException");
774*1449Stomee 	va_start(ap, fmt);
775*1449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
776*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
777*1449Stomee 	va_end(ap);
778*1449Stomee }
779*1449Stomee 
780*1449Stomee void
781*1449Stomee dtj_throw_illegal_argument(JNIEnv *jenv, const char *fmt, ...)
782*1449Stomee {
783*1449Stomee 	va_list ap;
784*1449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
785*1449Stomee 	    "java/lang/IllegalArgumentException");
786*1449Stomee 	va_start(ap, fmt);
787*1449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
788*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
789*1449Stomee 	va_end(ap);
790*1449Stomee }
791*1449Stomee 
792*1449Stomee void
793*1449Stomee dtj_throw_no_such_element(JNIEnv *jenv, const char *fmt, ...)
794*1449Stomee {
795*1449Stomee 	va_list ap;
796*1449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
797*1449Stomee 	    "java/util/NoSuchElementException");
798*1449Stomee 	va_start(ap, fmt);
799*1449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
800*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
801*1449Stomee 	va_end(ap);
802*1449Stomee }
803*1449Stomee 
804*1449Stomee void
805*1449Stomee dtj_throw_class_cast(JNIEnv *jenv, const char *fmt, ...)
806*1449Stomee {
807*1449Stomee 	va_list ap;
808*1449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
809*1449Stomee 	    "java/lang/ClassCastException");
810*1449Stomee 	va_start(ap, fmt);
811*1449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
812*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
813*1449Stomee 	va_end(ap);
814*1449Stomee }
815*1449Stomee 
816*1449Stomee void
817*1449Stomee dtj_throw_assertion(JNIEnv *jenv, const char *fmt, ...)
818*1449Stomee {
819*1449Stomee 	va_list ap;
820*1449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
821*1449Stomee 	    "java/lang/AssertionError");
822*1449Stomee 	va_start(ap, fmt);
823*1449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
824*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
825*1449Stomee 	va_end(ap);
826*1449Stomee }
827*1449Stomee 
828*1449Stomee void
829*1449Stomee dtj_throw_resource_limit(JNIEnv *jenv, const char *fmt, ...)
830*1449Stomee {
831*1449Stomee 	va_list ap;
832*1449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
833*1449Stomee 	    "org/opensolaris/os/dtrace/ResourceLimitException");
834*1449Stomee 	va_start(ap, fmt);
835*1449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
836*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
837*1449Stomee 	va_end(ap);
838*1449Stomee }
839*1449Stomee 
840*1449Stomee void
841*1449Stomee dtj_wrap_exception(JNIEnv *jenv, const char *file, int line)
842*1449Stomee {
843*1449Stomee 	jthrowable e = NULL;
844*1449Stomee 	jthrowable nx = NULL;
845*1449Stomee 	jstring jfile = NULL;
846*1449Stomee 
847*1449Stomee 	e = (*jenv)->ExceptionOccurred(jenv);
848*1449Stomee 	if (!e) {
849*1449Stomee 		return;
850*1449Stomee 	}
851*1449Stomee 
852*1449Stomee 	if (!g_dtj_load_common) {
853*1449Stomee 		return;
854*1449Stomee 	}
855*1449Stomee 
856*1449Stomee 	(*jenv)->ExceptionClear(jenv);
857*1449Stomee 
858*1449Stomee 	/* Unsafe to test while exception pending */
859*1449Stomee 	if ((*jenv)->IsInstanceOf(jenv, e, g_nx_jc)) {
860*1449Stomee 		/* Already wrapped */
861*1449Stomee 		(*jenv)->Throw(jenv, e);
862*1449Stomee 		(*jenv)->DeleteLocalRef(jenv, e);
863*1449Stomee 		return;
864*1449Stomee 	}
865*1449Stomee 
866*1449Stomee 	jfile = dtj_NewStringNative(jenv, file);
867*1449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
868*1449Stomee 		/*
869*1449Stomee 		 * Only wrap the exception if possible, otherwise just throw the
870*1449Stomee 		 * original exception.
871*1449Stomee 		 */
872*1449Stomee 		(*jenv)->ExceptionClear(jenv);
873*1449Stomee 		(*jenv)->Throw(jenv, e);
874*1449Stomee 		(*jenv)->DeleteLocalRef(jenv, e);
875*1449Stomee 		return;
876*1449Stomee 	}
877*1449Stomee 
878*1449Stomee 	nx = (jthrowable)(*jenv)->NewObject(jenv, g_nx_jc, g_nxinit_jm,
879*1449Stomee 	    jfile, line, e);
880*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, jfile);
881*1449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
882*1449Stomee 		(*jenv)->ExceptionClear(jenv);
883*1449Stomee 		(*jenv)->Throw(jenv, e);
884*1449Stomee 		(*jenv)->DeleteLocalRef(jenv, e);
885*1449Stomee 		return;
886*1449Stomee 	}
887*1449Stomee 
888*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, e);
889*1449Stomee 	(*jenv)->Throw(jenv, nx);
890*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, nx);
891*1449Stomee }
892*1449Stomee 
893*1449Stomee /*
894*1449Stomee  * Calls the given java object's toString() method and prints the value to
895*1449Stomee  * stdout.  Useful for debugging.  Guaranteed that no exception is pending when
896*1449Stomee  * this function returns.
897*1449Stomee  */
898*1449Stomee void
899*1449Stomee dtj_print_object(JNIEnv *jenv, jobject jobj)
900*1449Stomee {
901*1449Stomee 	jstring jstr;
902*1449Stomee 	const char *cstr;
903*1449Stomee 
904*1449Stomee 	if (!g_dtj_load_common) {
905*1449Stomee 		dtj_throw_illegal_state(jenv,
906*1449Stomee 		    "dtj_load_common() has not been called");
907*1449Stomee 		(*jenv)->ExceptionDescribe(jenv); /* clears the exception */
908*1449Stomee 		return;
909*1449Stomee 	}
910*1449Stomee 
911*1449Stomee 	if (!jobj) {
912*1449Stomee 		(void) printf("null\n");
913*1449Stomee 		return;
914*1449Stomee 	}
915*1449Stomee 
916*1449Stomee 	jstr = (*jenv)->CallObjectMethod(jenv, jobj, g_tostring_jm);
917*1449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
918*1449Stomee 		(*jenv)->ExceptionDescribe(jenv); /* clears the exception */
919*1449Stomee 		return;
920*1449Stomee 	}
921*1449Stomee 	cstr = (*jenv)->GetStringUTFChars(jenv, jstr, 0);
922*1449Stomee 	if (cstr) {
923*1449Stomee 		(void) printf("%s\n", cstr);
924*1449Stomee 	} else {
925*1449Stomee 		(*jenv)->ExceptionDescribe(jenv); /* clears the exception */
926*1449Stomee 		(*jenv)->DeleteLocalRef(jenv, jstr);
927*1449Stomee 		return;
928*1449Stomee 	}
929*1449Stomee 	(*jenv)->ReleaseStringUTFChars(jenv, jstr, cstr);
930*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, jstr);
931*1449Stomee }
932*1449Stomee 
933*1449Stomee jstring
934*1449Stomee dtj_format_string(JNIEnv *jenv, const char *fmt, ...)
935*1449Stomee {
936*1449Stomee 	va_list ap;
937*1449Stomee 	char str[DTJ_MSG_SIZE];
938*1449Stomee 
939*1449Stomee 	jstring jstr = NULL;
940*1449Stomee 
941*1449Stomee 	va_start(ap, fmt);
942*1449Stomee 	(void) vsnprintf(str, sizeof (str), fmt, ap);
943*1449Stomee 	va_end(ap);
944*1449Stomee 
945*1449Stomee 	jstr = dtj_NewStringNative(jenv, str);
946*1449Stomee 	/* return NULL if OutOfMemoryError pending */
947*1449Stomee 	return (jstr);
948*1449Stomee }
949*1449Stomee 
950*1449Stomee jstring
951*1449Stomee dtj_NewStringNative(JNIEnv *jenv, const char *str)
952*1449Stomee {
953*1449Stomee 	jstring result;
954*1449Stomee 	jbyteArray bytes = 0;
955*1449Stomee 	int len;
956*1449Stomee 
957*1449Stomee 	if (!g_dtj_load_common) {
958*1449Stomee 		dtj_throw_illegal_state(jenv,
959*1449Stomee 		    "dtj_load_common() has not been called");
960*1449Stomee 		return (NULL);
961*1449Stomee 	}
962*1449Stomee 
963*1449Stomee 	len = strlen(str);
964*1449Stomee 
965*1449Stomee 	bytes = (*jenv)->NewByteArray(jenv, len);
966*1449Stomee 	if (!bytes) {
967*1449Stomee 		return (NULL); /* OutOfMemoryError pending */
968*1449Stomee 	}
969*1449Stomee 	(*jenv)->SetByteArrayRegion(jenv, bytes, 0, len,
970*1449Stomee 	    (jbyte *)str);
971*1449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
972*1449Stomee 		(*jenv)->DeleteLocalRef(jenv, bytes);
973*1449Stomee 		return (NULL); /* ArrayIndexOutOfBoundsException pending */
974*1449Stomee 	}
975*1449Stomee 	result = (*jenv)->NewObject(jenv, g_string_jc, g_strinit_bytes_jm,
976*1449Stomee 	    bytes);
977*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, bytes);
978*1449Stomee 	/* return NULL result if exception pending */
979*1449Stomee 	return (result);
980*1449Stomee }
981*1449Stomee 
982*1449Stomee char *
983*1449Stomee dtj_GetStringNativeChars(JNIEnv *jenv, jstring jstr)
984*1449Stomee {
985*1449Stomee 	jbyteArray bytes = NULL;
986*1449Stomee 
987*1449Stomee 	jint len;
988*1449Stomee 	char *result = NULL;
989*1449Stomee 
990*1449Stomee 	if (!g_dtj_load_common) {
991*1449Stomee 		dtj_throw_illegal_state(jenv,
992*1449Stomee 		    "dtj_load_common() has not been called");
993*1449Stomee 		return (NULL);
994*1449Stomee 	}
995*1449Stomee 
996*1449Stomee 	bytes = (*jenv)->CallObjectMethod(jenv, jstr, g_strbytes_jm);
997*1449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
998*1449Stomee 		return (NULL); /* OutOfMemoryError pending */
999*1449Stomee 	}
1000*1449Stomee 	/* Does not throw exceptions */
1001*1449Stomee 	len = (*jenv)->GetArrayLength(jenv, bytes);
1002*1449Stomee 	result = malloc(len + 1);
1003*1449Stomee 	if (!result) {
1004*1449Stomee 		(*jenv)->DeleteLocalRef(jenv, bytes);
1005*1449Stomee 		dtj_throw_out_of_memory(jenv,
1006*1449Stomee 		    "could not allocate native chars");
1007*1449Stomee 		return (NULL);
1008*1449Stomee 	}
1009*1449Stomee 
1010*1449Stomee 	/* Skip check for ArrayIndexOutOfBoundsException */
1011*1449Stomee 	(*jenv)->GetByteArrayRegion(jenv, bytes, 0, len,
1012*1449Stomee 	    (jbyte *)result);
1013*1449Stomee 	(*jenv)->DeleteLocalRef(jenv, bytes);
1014*1449Stomee 	result[len] = '\0'; /* NUL-terminate */
1015*1449Stomee 
1016*1449Stomee 	return (result);
1017*1449Stomee }
1018*1449Stomee 
1019*1449Stomee void
1020*1449Stomee /* ARGSUSED */
1021*1449Stomee dtj_ReleaseStringNativeChars(JNIEnv *jenv, jstring jstr, const char *str)
1022*1449Stomee {
1023*1449Stomee 	free((void *)str);
1024*1449Stomee }
1025*1449Stomee 
1026*1449Stomee char **
1027*1449Stomee dtj_get_argv(JNIEnv *jenv, jobjectArray args, int *argc)
1028*1449Stomee {
1029*1449Stomee 	char **argv = NULL; /* return value */
1030*1449Stomee 	const char *str;
1031*1449Stomee 	int i;
1032*1449Stomee 
1033*1449Stomee 	jstring jstr = NULL;
1034*1449Stomee 
1035*1449Stomee 	if (!g_dtj_load_common) {
1036*1449Stomee 		dtj_throw_illegal_state(jenv,
1037*1449Stomee 		    "dtj_load_common() has not been called");
1038*1449Stomee 		return (NULL);
1039*1449Stomee 	}
1040*1449Stomee 
1041*1449Stomee 	*argc = (*jenv)->GetArrayLength(jenv, args);
1042*1449Stomee 	/*
1043*1449Stomee 	 * Initialize all string pointers to NULL so that in case of an error
1044*1449Stomee 	 * filling in the array, free_argv() will not attempt to free the
1045*1449Stomee 	 * unallocated elements.  Also NULL-terminate the string array for
1046*1449Stomee 	 * functions that expect terminating NULL rather than rely on argc.
1047*1449Stomee 	 */
1048*1449Stomee 	argv = uu_zalloc((sizeof (char *)) * (*argc + 1));
1049*1449Stomee 	if (!argv) {
1050*1449Stomee 		dtj_throw_out_of_memory(jenv, "Failed to allocate args array");
1051*1449Stomee 		return (NULL);
1052*1449Stomee 	}
1053*1449Stomee 
1054*1449Stomee 	for (i = 0; i < *argc; ++i) {
1055*1449Stomee 		jstr = (*jenv)->GetObjectArrayElement(jenv, args, i);
1056*1449Stomee 		if ((*jenv)->ExceptionCheck(jenv)) {
1057*1449Stomee 			dtj_free_argv(argv);
1058*1449Stomee 			return (NULL);
1059*1449Stomee 		}
1060*1449Stomee 		str = dtj_GetStringNativeChars(jenv, jstr);
1061*1449Stomee 		if ((*jenv)->ExceptionCheck(jenv)) {
1062*1449Stomee 			dtj_free_argv(argv);
1063*1449Stomee 			(*jenv)->DeleteLocalRef(jenv, jstr);
1064*1449Stomee 			return (NULL);
1065*1449Stomee 		}
1066*1449Stomee 		argv[i] = malloc(strlen(str) + 1);
1067*1449Stomee 		if (!argv[i]) {
1068*1449Stomee 			dtj_throw_out_of_memory(jenv, "Failed to allocate arg");
1069*1449Stomee 			dtj_free_argv(argv);
1070*1449Stomee 			dtj_ReleaseStringNativeChars(jenv, jstr, str);
1071*1449Stomee 			(*jenv)->DeleteLocalRef(jenv, jstr);
1072*1449Stomee 			return (NULL);
1073*1449Stomee 		}
1074*1449Stomee 		(void) strcpy(argv[i], str);
1075*1449Stomee 		dtj_ReleaseStringNativeChars(jenv, jstr, str);
1076*1449Stomee 		(*jenv)->DeleteLocalRef(jenv, jstr);
1077*1449Stomee 		jstr = NULL;
1078*1449Stomee 	}
1079*1449Stomee 
1080*1449Stomee 	return (argv);
1081*1449Stomee }
1082*1449Stomee 
1083*1449Stomee char **
1084*1449Stomee dtj_make_argv(JNIEnv *jenv, jstring command, int *argc)
1085*1449Stomee {
1086*1449Stomee 	const char *ws = "\f\n\r\t\v ";
1087*1449Stomee 	char **argv = NULL; /* return value */
1088*1449Stomee 	const char *cmd; /* native command string */
1089*1449Stomee 	char *s; /* writable command */
1090*1449Stomee 	char *tok; /* token */
1091*1449Stomee 	int len;
1092*1449Stomee 
1093*1449Stomee 	if (!g_dtj_load_common) {
1094*1449Stomee 		dtj_throw_illegal_state(jenv,
1095*1449Stomee 		    "dtj_load_common() has not been called");
1096*1449Stomee 		return (NULL);
1097*1449Stomee 	}
1098*1449Stomee 
1099*1449Stomee 	if (!command) {
1100*1449Stomee 		dtj_throw_null_pointer(jenv, "command is null");
1101*1449Stomee 		return (NULL);
1102*1449Stomee 	} else if ((*jenv)->GetStringLength(jenv, command) == 0) {
1103*1449Stomee 		dtj_throw_illegal_argument(jenv, "command is empty");
1104*1449Stomee 		return (NULL);
1105*1449Stomee 	}
1106*1449Stomee 
1107*1449Stomee 	cmd = dtj_GetStringNativeChars(jenv, command);
1108*1449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
1109*1449Stomee 		return (NULL);
1110*1449Stomee 	}
1111*1449Stomee 	len = strlen(cmd);
1112*1449Stomee 	s = malloc(len + 1);
1113*1449Stomee 	if (!s) {
1114*1449Stomee 		dtj_throw_out_of_memory(jenv,
1115*1449Stomee 		    "failed to allocate command string");
1116*1449Stomee 		dtj_ReleaseStringNativeChars(jenv, command, cmd);
1117*1449Stomee 		return (NULL);
1118*1449Stomee 	}
1119*1449Stomee 	(void) strcpy(s, cmd);
1120*1449Stomee 	/*
1121*1449Stomee 	 * Initialize all string pointers to NULL so that in case of an error
1122*1449Stomee 	 * filling in the array, free_argv() will not attempt to free the
1123*1449Stomee 	 * unallocated elements.  Also NULL-terminate the string array for
1124*1449Stomee 	 * functions that expect terminating NULL rather than rely on argc.
1125*1449Stomee 	 * Allow for maximum length resulting from single-character tokens
1126*1449Stomee 	 * separated by single spaces.
1127*1449Stomee 	 */
1128*1449Stomee 	argv = uu_zalloc(sizeof (char *) * (len / 2 + 1));
1129*1449Stomee 	if (!argv) {
1130*1449Stomee 		dtj_throw_out_of_memory(jenv, "failed to allocate args array");
1131*1449Stomee 		free(s);
1132*1449Stomee 		dtj_ReleaseStringNativeChars(jenv, command, cmd);
1133*1449Stomee 		return (NULL);
1134*1449Stomee 	}
1135*1449Stomee 
1136*1449Stomee 	*argc = 0;
1137*1449Stomee 	for (tok = strtok(s, ws); tok != NULL; tok = strtok(NULL, ws)) {
1138*1449Stomee 		argv[*argc] = malloc(strlen(tok) + 1);
1139*1449Stomee 		if (!argv[*argc]) {
1140*1449Stomee 			dtj_throw_out_of_memory(jenv, "Failed to allocate arg");
1141*1449Stomee 			dtj_free_argv(argv);
1142*1449Stomee 			free(s);
1143*1449Stomee 			dtj_ReleaseStringNativeChars(jenv, command, cmd);
1144*1449Stomee 			return (NULL);
1145*1449Stomee 		}
1146*1449Stomee 		(void) strcpy(argv[(*argc)++], tok);
1147*1449Stomee 	}
1148*1449Stomee 
1149*1449Stomee 	if (*argc == 0) {
1150*1449Stomee 		dtj_throw_illegal_argument(jenv, "command is blank");
1151*1449Stomee 		dtj_free_argv(argv);
1152*1449Stomee 		free(s);
1153*1449Stomee 		dtj_ReleaseStringNativeChars(jenv, command, cmd);
1154*1449Stomee 		return (NULL);
1155*1449Stomee 	}
1156*1449Stomee 
1157*1449Stomee 	free(s);
1158*1449Stomee 	dtj_ReleaseStringNativeChars(jenv, command, cmd);
1159*1449Stomee 	return (argv);
1160*1449Stomee }
1161*1449Stomee 
1162*1449Stomee void
1163*1449Stomee dtj_free_argv(char **argv)
1164*1449Stomee {
1165*1449Stomee 	if (argv) {
1166*1449Stomee 		char **s = argv;
1167*1449Stomee 		while (*s) {
1168*1449Stomee 			free((void *)*s);
1169*1449Stomee 			*s++ = NULL;
1170*1449Stomee 		}
1171*1449Stomee 		free((void *)argv);
1172*1449Stomee 	}
1173*1449Stomee }
1174*1449Stomee 
1175*1449Stomee 
1176*1449Stomee /* Wrappers for uu_list_t */
1177*1449Stomee 
1178*1449Stomee int
1179*1449Stomee /* ARGSUSED */
1180*1449Stomee dtj_pointer_list_entry_cmp(const void *v1, const void *v2, void *arg)
1181*1449Stomee {
1182*1449Stomee 	const dtj_pointer_list_entry_t *p1 = v1;
1183*1449Stomee 	const dtj_pointer_list_entry_t *p2 = v2;
1184*1449Stomee 
1185*1449Stomee 	/*
1186*1449Stomee 	 * It is not valid to compare pointers using the relational operators
1187*1449Stomee 	 * unless they point to elements in the same array.
1188*1449Stomee 	 */
1189*1449Stomee 	uint64_t x = (uint64_t)p1->dple_ptr;
1190*1449Stomee 	uint64_t y = (uint64_t)p2->dple_ptr;
1191*1449Stomee 	int rc;
1192*1449Stomee 	rc = ((x > y) ? 1 : ((x < y) ? -1 : 0));
1193*1449Stomee 	return (rc);
1194*1449Stomee }
1195*1449Stomee 
1196*1449Stomee int
1197*1449Stomee /* ARGSUSED */
1198*1449Stomee dtj_string_list_entry_cmp(const void *v1, const void *v2, void *arg)
1199*1449Stomee {
1200*1449Stomee 	const dtj_string_list_entry_t *p1 = v1;
1201*1449Stomee 	const dtj_string_list_entry_t *p2 = v2;
1202*1449Stomee 	const char *s1 = p1->dsle_value;
1203*1449Stomee 	const char *s2 = p2->dsle_value;
1204*1449Stomee 	if (s1 == NULL) {
1205*1449Stomee 		return (s2 == NULL ? 0 : -1);
1206*1449Stomee 	}
1207*1449Stomee 	if (s2 == NULL) {
1208*1449Stomee 		return (1);
1209*1449Stomee 	}
1210*1449Stomee 	return (strcmp(s1, s2));
1211*1449Stomee }
1212*1449Stomee 
1213*1449Stomee static boolean_t
1214*1449Stomee dtj_check_pointer_pool(void)
1215*1449Stomee {
1216*1449Stomee 	if (g_pointer_pool == NULL) {
1217*1449Stomee 		g_pointer_pool = uu_list_pool_create("g_pointer_pool",
1218*1449Stomee 		    sizeof (dtj_pointer_list_entry_t),
1219*1449Stomee 		    offsetof(dtj_pointer_list_entry_t, dple_node),
1220*1449Stomee 		    dtj_pointer_list_entry_cmp,
1221*1449Stomee 		    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
1222*1449Stomee 		if (g_pointer_pool == NULL) {
1223*1449Stomee 			return (B_FALSE);
1224*1449Stomee 		}
1225*1449Stomee 	}
1226*1449Stomee 	return (B_TRUE);
1227*1449Stomee }
1228*1449Stomee 
1229*1449Stomee uu_list_t *
1230*1449Stomee dtj_pointer_list_create(void)
1231*1449Stomee {
1232*1449Stomee 	uu_list_t *list;
1233*1449Stomee 
1234*1449Stomee 	if (!dtj_check_pointer_pool()) {
1235*1449Stomee 		return (NULL);
1236*1449Stomee 	}
1237*1449Stomee 
1238*1449Stomee 	list = uu_list_create(g_pointer_pool, NULL,
1239*1449Stomee 	    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
1240*1449Stomee 	return (list);
1241*1449Stomee }
1242*1449Stomee 
1243*1449Stomee dtj_pointer_list_entry_t *
1244*1449Stomee dtj_pointer_list_entry_create(void *p)
1245*1449Stomee {
1246*1449Stomee 	dtj_pointer_list_entry_t *e;
1247*1449Stomee 
1248*1449Stomee 	if (!dtj_check_pointer_pool()) {
1249*1449Stomee 		return (NULL);
1250*1449Stomee 	}
1251*1449Stomee 
1252*1449Stomee 	e = uu_zalloc(sizeof (dtj_pointer_list_entry_t));
1253*1449Stomee 	if (e) {
1254*1449Stomee 		uu_list_node_init(e, &e->dple_node, g_pointer_pool);
1255*1449Stomee 		e->dple_ptr = p;
1256*1449Stomee 	}
1257*1449Stomee 	return (e);
1258*1449Stomee }
1259*1449Stomee 
1260*1449Stomee static boolean_t
1261*1449Stomee dtj_check_string_pool(void)
1262*1449Stomee {
1263*1449Stomee 	if (g_string_pool == NULL) {
1264*1449Stomee 		g_string_pool = uu_list_pool_create("g_string_pool",
1265*1449Stomee 		    sizeof (dtj_string_list_entry_t),
1266*1449Stomee 		    offsetof(dtj_string_list_entry_t, dsle_node),
1267*1449Stomee 		    dtj_string_list_entry_cmp,
1268*1449Stomee 		    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
1269*1449Stomee 		if (g_string_pool == NULL) {
1270*1449Stomee 			return (B_FALSE);
1271*1449Stomee 		}
1272*1449Stomee 	}
1273*1449Stomee 	return (B_TRUE);
1274*1449Stomee }
1275*1449Stomee 
1276*1449Stomee uu_list_t *
1277*1449Stomee dtj_string_list_create(void)
1278*1449Stomee {
1279*1449Stomee 	uu_list_t *list;
1280*1449Stomee 
1281*1449Stomee 	if (!dtj_check_string_pool()) {
1282*1449Stomee 		return (NULL);
1283*1449Stomee 	}
1284*1449Stomee 
1285*1449Stomee 	list = uu_list_create(g_string_pool, NULL,
1286*1449Stomee 	    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
1287*1449Stomee 	return (list);
1288*1449Stomee }
1289*1449Stomee 
1290*1449Stomee dtj_string_list_entry_t *
1291*1449Stomee dtj_string_list_entry_create(const char *s)
1292*1449Stomee {
1293*1449Stomee 	dtj_string_list_entry_t *e;
1294*1449Stomee 
1295*1449Stomee 	if (!dtj_check_string_pool()) {
1296*1449Stomee 		return (NULL);
1297*1449Stomee 	}
1298*1449Stomee 
1299*1449Stomee 	e = uu_zalloc(sizeof (dtj_string_list_entry_t));
1300*1449Stomee 	if (e) {
1301*1449Stomee 		uu_list_node_init(e, &e->dsle_node, g_string_pool);
1302*1449Stomee 		if (s) {
1303*1449Stomee 			e->dsle_value = malloc(strlen(s) + 1);
1304*1449Stomee 			if (e->dsle_value) {
1305*1449Stomee 				(void) strcpy(e->dsle_value, s);
1306*1449Stomee 			} else {
1307*1449Stomee 				uu_list_node_fini(e, &e->dsle_node,
1308*1449Stomee 				    g_string_pool);
1309*1449Stomee 				uu_free(e);
1310*1449Stomee 				e = NULL;
1311*1449Stomee 			}
1312*1449Stomee 		}
1313*1449Stomee 	}
1314*1449Stomee 	return (e);
1315*1449Stomee }
1316*1449Stomee 
1317*1449Stomee void
1318*1449Stomee dtj_pointer_list_entry_destroy(void *v,
1319*1449Stomee     dtj_value_destroy_f *value_destroy, void *arg)
1320*1449Stomee {
1321*1449Stomee 	if (v) {
1322*1449Stomee 		dtj_pointer_list_entry_t *e = v;
1323*1449Stomee 		if (value_destroy) {
1324*1449Stomee 			value_destroy(e->dple_ptr, arg);
1325*1449Stomee 		}
1326*1449Stomee 		uu_list_node_fini(e, &e->dple_node, g_pointer_pool);
1327*1449Stomee 		e->dple_ptr = NULL;
1328*1449Stomee 		uu_free(v);
1329*1449Stomee 	}
1330*1449Stomee }
1331*1449Stomee 
1332*1449Stomee void
1333*1449Stomee /* ARGSUSED */
1334*1449Stomee dtj_string_list_entry_destroy(void *v, void *arg)
1335*1449Stomee {
1336*1449Stomee 	if (v) {
1337*1449Stomee 		dtj_string_list_entry_t *e = v;
1338*1449Stomee 		free(e->dsle_value);
1339*1449Stomee 		uu_list_node_fini(e, &e->dsle_node, g_string_pool);
1340*1449Stomee 		e->dsle_value = NULL;
1341*1449Stomee 		uu_free(v);
1342*1449Stomee 	}
1343*1449Stomee }
1344*1449Stomee 
1345*1449Stomee void
1346*1449Stomee dtj_list_clear(uu_list_t *list, dtj_value_destroy_f *value_destroy,
1347*1449Stomee     void *arg)
1348*1449Stomee {
1349*1449Stomee 	void *cookie; /* needed for uu_list_teardown */
1350*1449Stomee 	void *value;
1351*1449Stomee 
1352*1449Stomee 	if (!list) {
1353*1449Stomee 		return;
1354*1449Stomee 	}
1355*1449Stomee 
1356*1449Stomee 	cookie = NULL;
1357*1449Stomee 	if (value_destroy) {
1358*1449Stomee 		while ((value = uu_list_teardown(list, &cookie)) != NULL) {
1359*1449Stomee 			value_destroy(value, arg);
1360*1449Stomee 		}
1361*1449Stomee 	} else {
1362*1449Stomee 		while ((value = uu_list_teardown(list, &cookie)) != NULL) {
1363*1449Stomee 		}
1364*1449Stomee 	}
1365*1449Stomee }
1366*1449Stomee 
1367*1449Stomee void
1368*1449Stomee dtj_list_destroy(uu_list_t *list,
1369*1449Stomee     dtj_value_destroy_f *value_destroy, void *arg)
1370*1449Stomee {
1371*1449Stomee 	dtj_list_clear(list, value_destroy, arg);
1372*1449Stomee 	uu_list_destroy(list);
1373*1449Stomee }
1374*1449Stomee 
1375*1449Stomee void
1376*1449Stomee dtj_pointer_list_clear(uu_list_t *list,
1377*1449Stomee     dtj_value_destroy_f *value_destroy, void *arg)
1378*1449Stomee {
1379*1449Stomee 	void *cookie; /* needed for uu_list_teardown */
1380*1449Stomee 	dtj_pointer_list_entry_t *e;
1381*1449Stomee 
1382*1449Stomee 	if (!list) {
1383*1449Stomee 		return;
1384*1449Stomee 	}
1385*1449Stomee 
1386*1449Stomee 	cookie = NULL;
1387*1449Stomee 	while ((e = uu_list_teardown(list, &cookie)) != NULL) {
1388*1449Stomee 		dtj_pointer_list_entry_destroy(e, value_destroy, arg);
1389*1449Stomee 	}
1390*1449Stomee }
1391*1449Stomee 
1392*1449Stomee void
1393*1449Stomee dtj_pointer_list_destroy(uu_list_t *list,
1394*1449Stomee     dtj_value_destroy_f *value_destroy, void *arg)
1395*1449Stomee {
1396*1449Stomee 	dtj_pointer_list_clear(list, value_destroy, arg);
1397*1449Stomee 	uu_list_destroy(list);
1398*1449Stomee }
1399*1449Stomee 
1400*1449Stomee void
1401*1449Stomee dtj_string_list_clear(uu_list_t *list)
1402*1449Stomee {
1403*1449Stomee 	dtj_list_clear(list, dtj_string_list_entry_destroy, NULL);
1404*1449Stomee }
1405*1449Stomee 
1406*1449Stomee void
1407*1449Stomee dtj_string_list_destroy(uu_list_t *list)
1408*1449Stomee {
1409*1449Stomee 	dtj_list_destroy(list, dtj_string_list_entry_destroy, NULL);
1410*1449Stomee }
1411*1449Stomee 
1412*1449Stomee boolean_t
1413*1449Stomee dtj_list_empty(uu_list_t *list)
1414*1449Stomee {
1415*1449Stomee 	return (uu_list_numnodes(list) == 0);
1416*1449Stomee }
1417*1449Stomee 
1418*1449Stomee boolean_t
1419*1449Stomee dtj_list_add(uu_list_t *list, void *value)
1420*1449Stomee {
1421*1449Stomee 	return (uu_list_insert_before(list, NULL, value) == 0);
1422*1449Stomee }
1423*1449Stomee 
1424*1449Stomee boolean_t
1425*1449Stomee dtj_pointer_list_add(uu_list_t *list, void *p)
1426*1449Stomee {
1427*1449Stomee 	dtj_pointer_list_entry_t *e = dtj_pointer_list_entry_create(p);
1428*1449Stomee 	if (!e) {
1429*1449Stomee 		return (B_FALSE);
1430*1449Stomee 	}
1431*1449Stomee 	return (dtj_list_add(list, e));
1432*1449Stomee }
1433*1449Stomee 
1434*1449Stomee void *
1435*1449Stomee dtj_pointer_list_walk_next(uu_list_walk_t *itr)
1436*1449Stomee {
1437*1449Stomee 	dtj_pointer_list_entry_t *e = uu_list_walk_next(itr);
1438*1449Stomee 	if (!e) {
1439*1449Stomee 		return (DTJ_INVALID_PTR);
1440*1449Stomee 	}
1441*1449Stomee 	return (e->dple_ptr);
1442*1449Stomee }
1443*1449Stomee 
1444*1449Stomee void *
1445*1449Stomee dtj_pointer_list_first(uu_list_t *list)
1446*1449Stomee {
1447*1449Stomee 	dtj_pointer_list_entry_t *e = uu_list_first(list);
1448*1449Stomee 	if (!e) {
1449*1449Stomee 		/* NULL is a valid value; use -1 for invalid */
1450*1449Stomee 		return (DTJ_INVALID_PTR);
1451*1449Stomee 	}
1452*1449Stomee 	return (e->dple_ptr);
1453*1449Stomee }
1454*1449Stomee 
1455*1449Stomee void *
1456*1449Stomee dtj_pointer_list_last(uu_list_t *list)
1457*1449Stomee {
1458*1449Stomee 	dtj_pointer_list_entry_t *e = uu_list_last(list);
1459*1449Stomee 	if (!e) {
1460*1449Stomee 		/* NULL is a valid value; use -1 for invalid */
1461*1449Stomee 		return (DTJ_INVALID_PTR);
1462*1449Stomee 	}
1463*1449Stomee 	return (e->dple_ptr);
1464*1449Stomee }
1465*1449Stomee 
1466*1449Stomee boolean_t
1467*1449Stomee dtj_string_list_add(uu_list_t *list, const char *s)
1468*1449Stomee {
1469*1449Stomee 	dtj_string_list_entry_t *e = dtj_string_list_entry_create(s);
1470*1449Stomee 	if (!e) {
1471*1449Stomee 		return (B_FALSE);
1472*1449Stomee 	}
1473*1449Stomee 	return (dtj_list_add(list, e));
1474*1449Stomee }
1475*1449Stomee 
1476*1449Stomee const char *
1477*1449Stomee dtj_string_list_walk_next(uu_list_walk_t *itr)
1478*1449Stomee {
1479*1449Stomee 	dtj_string_list_entry_t *e = uu_list_walk_next(itr);
1480*1449Stomee 	if (!e) {
1481*1449Stomee 		return (DTJ_INVALID_STR);
1482*1449Stomee 	}
1483*1449Stomee 	return (e->dsle_value);
1484*1449Stomee }
1485*1449Stomee 
1486*1449Stomee const char *
1487*1449Stomee dtj_string_list_first(uu_list_t *list)
1488*1449Stomee {
1489*1449Stomee 	dtj_string_list_entry_t *e = uu_list_first(list);
1490*1449Stomee 	if (!e) {
1491*1449Stomee 		/* NULL is a valid string value; use -1 for invalid */
1492*1449Stomee 		return (DTJ_INVALID_STR);
1493*1449Stomee 	}
1494*1449Stomee 	return (e->dsle_value);
1495*1449Stomee }
1496*1449Stomee 
1497*1449Stomee const char *
1498*1449Stomee dtj_string_list_last(uu_list_t *list)
1499*1449Stomee {
1500*1449Stomee 	dtj_string_list_entry_t *e = uu_list_last(list);
1501*1449Stomee 	if (!e) {
1502*1449Stomee 		/* NULL is a valid string value; use -1 for invalid */
1503*1449Stomee 		return (DTJ_INVALID_STR);
1504*1449Stomee 	}
1505*1449Stomee 	return (e->dsle_value);
1506*1449Stomee }
1507