xref: /onnv-gate/usr/src/lib/libdtrace_jni/common/dtj_util.c (revision 6136:b1f0a0698377)
11449Stomee /*
21449Stomee  * CDDL HEADER START
31449Stomee  *
41449Stomee  * The contents of this file are subject to the terms of the
51449Stomee  * Common Development and Distribution License (the "License").
61449Stomee  * You may not use this file except in compliance with the License.
71449Stomee  *
81449Stomee  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91449Stomee  * or http://www.opensolaris.org/os/licensing.
101449Stomee  * See the License for the specific language governing permissions
111449Stomee  * and limitations under the License.
121449Stomee  *
131449Stomee  * When distributing Covered Code, include this CDDL HEADER in each
141449Stomee  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151449Stomee  * If applicable, add the following below this CDDL HEADER, with the
161449Stomee  * fields enclosed by brackets "[]" replaced with your own identifying
171449Stomee  * information: Portions Copyright [yyyy] [name of copyright owner]
181449Stomee  *
191449Stomee  * CDDL HEADER END
201449Stomee  */
211449Stomee 
221449Stomee /*
23*6136Stomee  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241449Stomee  * Use is subject to license terms.
251449Stomee  */
261449Stomee 
271449Stomee #pragma ident	"%Z%%M%	%I%	%E% SMI"
281449Stomee 
291449Stomee #include <stdlib.h>
301449Stomee #include <stddef.h>
311449Stomee #include <sys/types.h>
321449Stomee #include <pthread.h>
331449Stomee #include <string.h>
341449Stomee #include <dtj_util.h>
351449Stomee 
361449Stomee /*
371449Stomee  * dtj_util.c separates functionality that is generally useful from
381449Stomee  * that which is specific to the Java DTrace API.  If moved to a separate
391449Stomee  * library, this functionality could be shared by other JNI wrappers.
401449Stomee  */
411449Stomee 
421449Stomee boolean_t g_dtj_util_debug = B_FALSE;
431449Stomee static boolean_t g_dtj_load_common = B_FALSE;
441449Stomee 
451449Stomee /* NativeException */
461449Stomee jclass g_nx_jc = 0;
471449Stomee jmethodID g_nxinit_jm = 0;
481449Stomee 
491449Stomee /* java.io.Serializable */
501449Stomee jclass g_serial_jc = 0;
511449Stomee 
521449Stomee /* java.lang.Number */
531449Stomee jclass g_number_jc = 0;
541449Stomee jmethodID g_shortval_jm = 0;
551449Stomee jmethodID g_intval_jm = 0;
561449Stomee jmethodID g_longval_jm = 0;
571449Stomee 
581449Stomee /* java.lang.Byte */
591449Stomee jclass g_byte_jc = 0;
601449Stomee jmethodID g_byteinit_jm = 0;
611449Stomee 
621449Stomee /* java.lang.Character */
631449Stomee jclass g_char_jc = 0;
641449Stomee jmethodID g_charinit_jm = 0;
651449Stomee jmethodID g_charval_jm = 0;
661449Stomee 
671449Stomee /* java.lang.Short */
681449Stomee jclass g_short_jc = 0;
691449Stomee jmethodID g_shortinit_jm = 0;
701449Stomee 
711449Stomee /* java.lang.Integer */
721449Stomee jclass g_int_jc = 0;
731449Stomee jmethodID g_intinit_jm = 0;
741449Stomee 
751449Stomee /* java.lang.Long */
761449Stomee jclass g_long_jc = 0;
771449Stomee jmethodID g_longinit_jm = 0;
781449Stomee 
79*6136Stomee /* java.math.BigInteger */
80*6136Stomee jclass g_bigint_jc = 0;
81*6136Stomee jmethodID g_bigint_val_jsm = 0;
82*6136Stomee jmethodID g_bigint_div_jm = 0;
83*6136Stomee jmethodID g_bigint_shl_jm = 0;
84*6136Stomee jmethodID g_bigint_or_jm = 0;
85*6136Stomee jmethodID g_bigint_setbit_jm = 0;
86*6136Stomee 
871449Stomee /* java.lang.String */
881449Stomee jclass g_string_jc = 0;
891449Stomee jmethodID g_strinit_bytes_jm = 0;
901449Stomee jmethodID g_strbytes_jm = 0;
911449Stomee jmethodID g_trim_jm = 0;
921449Stomee 
933645Stomee /* java.lang.StringBuilder */
941449Stomee jclass g_buf_jc = 0;
951449Stomee jmethodID g_bufinit_jm = 0;
961449Stomee jmethodID g_buf_append_char_jm = 0;
971449Stomee jmethodID g_buf_append_int_jm = 0;
981449Stomee jmethodID g_buf_append_long_jm = 0;
991449Stomee jmethodID g_buf_append_str_jm = 0;
1001449Stomee jmethodID g_buf_append_obj_jm = 0;
1011449Stomee jmethodID g_buflen_jm = 0;
1021449Stomee jmethodID g_bufsetlen_jm = 0;
1031449Stomee 
1041449Stomee /* java.lang.Object */
1051449Stomee jclass g_object_jc = 0;
1061449Stomee jmethodID g_tostring_jm = 0;
1071449Stomee jmethodID g_equals_jm = 0;
1081449Stomee 
1091449Stomee /* java.lang.Enum */
1101449Stomee jclass g_enum_jc = 0;
1111449Stomee jmethodID g_enumname_jm = 0;
1121449Stomee 
1131449Stomee /* List */
1141449Stomee jclass g_list_jc = 0;
1151449Stomee jmethodID g_listclear_jm = 0;
1161449Stomee jmethodID g_listadd_jm = 0;
1171449Stomee jmethodID g_listget_jm = 0;
1181449Stomee jmethodID g_listsize_jm = 0;
1191449Stomee 
1201449Stomee /* Global list pools */
1211449Stomee static uu_list_pool_t *g_pointer_pool = NULL;
1221449Stomee static uu_list_pool_t *g_string_pool = NULL;
1231449Stomee 
1241449Stomee static dtj_status_t dtj_get_jni_classes(JNIEnv *, uu_list_t *, uu_list_pool_t *,
1251449Stomee     uu_list_pool_t *, uu_list_pool_t *, const dtj_table_entry_t *);
1261449Stomee static dtj_status_t dtj_cache_jni_methods(JNIEnv *, dtj_java_class_t *);
1271449Stomee static dtj_status_t dtj_cache_jni_fields(JNIEnv *, dtj_java_class_t *);
1281449Stomee 
1291449Stomee /* Constructors */
1301449Stomee static dtj_java_class_t *dtj_java_class_create(JNIEnv *, jclass *, char *,
1311449Stomee     uu_list_pool_t *, uu_list_pool_t *, uu_list_pool_t *);
1321449Stomee static dtj_java_method_t *dtj_java_method_create(JNIEnv *, jmethodID *, char *,
1331449Stomee     char *, uu_list_pool_t *);
1341449Stomee static dtj_java_method_t *dtj_java_static_method_create(JNIEnv *, jmethodID *,
1351449Stomee     char *, char *, uu_list_pool_t *);
1361449Stomee static dtj_java_field_t *dtj_java_field_create(JNIEnv *, jfieldID *, char *,
1371449Stomee     char *, uu_list_pool_t *);
1381449Stomee static dtj_java_field_t *dtj_java_static_field_create(JNIEnv *, jfieldID *,
1391449Stomee     char *, char *, uu_list_pool_t *);
1401449Stomee 
1411449Stomee /* Destructors */
1421449Stomee static void dtj_java_class_destroy(void *, void *);
1431449Stomee static void dtj_java_method_destroy(void *, void *);
1441449Stomee static void dtj_java_field_destroy(void *, void *);
1451449Stomee 
1461449Stomee /* Comparison functions, uu_compare_fn_t signature */
1471449Stomee static int dtj_java_class_cmp(const void *, const void *, void *);
1481449Stomee static int dtj_java_method_cmp(const void *, const void *, void *);
1491449Stomee static int dtj_java_field_cmp(const void *, const void *, void *);
1501449Stomee 
1511449Stomee /* Java Throwable */
1521449Stomee static void dtj_throw(JNIEnv *, jclass, const char *, va_list *);
1531449Stomee 
1541449Stomee /* Support for uu_list_t wrappers */
1551449Stomee static boolean_t dtj_check_pointer_pool(void);
1561449Stomee static boolean_t dtj_check_string_pool(void);
1571449Stomee 
1581449Stomee dtj_status_t
dtj_load_common(JNIEnv * jenv)1591449Stomee dtj_load_common(JNIEnv *jenv)
1601449Stomee {
1611449Stomee 	dtj_status_t status;
1621449Stomee 
1631449Stomee 	static const dtj_table_entry_t table[] = {
1641449Stomee 		/* NativeException */
1651449Stomee 		{ JCLASS,  &g_nx_jc,
1661449Stomee 			"org/opensolaris/os/dtrace/NativeException" },
1671449Stomee 		{ JMETHOD, &g_nxinit_jm, CONSTRUCTOR,
1681449Stomee 			"(Ljava/lang/String;ILjava/lang/Throwable;)V" },
1691449Stomee 
1701449Stomee 		/* java.io.Serializable */
1711449Stomee 		{ JCLASS,  &g_serial_jc, "java/io/Serializable" },
1721449Stomee 
1731449Stomee 		/* java.lang.Number */
1741449Stomee 		{ JCLASS,  &g_number_jc, "java/lang/Number" },
1751449Stomee 		{ JMETHOD, &g_shortval_jm, "shortValue", "()S" },
1761449Stomee 		{ JMETHOD, &g_intval_jm, "intValue", "()I" },
1771449Stomee 		{ JMETHOD, &g_longval_jm, "longValue", "()J" },
1781449Stomee 
1791449Stomee 		/* java.lang.Byte */
1801449Stomee 		{ JCLASS,  &g_byte_jc, "java/lang/Byte" },
1811449Stomee 		{ JMETHOD, &g_byteinit_jm, CONSTRUCTOR, "(B)V" },
1821449Stomee 
1831449Stomee 		/* java.lang.Character */
1841449Stomee 		{ JCLASS,  &g_char_jc, "java/lang/Character" },
1851449Stomee 		{ JMETHOD, &g_charinit_jm, CONSTRUCTOR, "(C)V" },
1861449Stomee 		{ JMETHOD, &g_charval_jm, "charValue", "()C" },
1871449Stomee 
1881449Stomee 		/* java.lang.Short */
1891449Stomee 		{ JCLASS,  &g_short_jc, "java/lang/Short" },
1901449Stomee 		{ JMETHOD, &g_shortinit_jm, CONSTRUCTOR, "(S)V" },
1911449Stomee 
1921449Stomee 		/* java.lang.Integer */
1931449Stomee 		{ JCLASS,  &g_int_jc, "java/lang/Integer" },
1941449Stomee 		{ JMETHOD, &g_intinit_jm, CONSTRUCTOR, "(I)V" },
1951449Stomee 
1961449Stomee 		/* java.lang.Long */
1971449Stomee 		{ JCLASS,  &g_long_jc, "java/lang/Long" },
1981449Stomee 		{ JMETHOD, &g_longinit_jm, CONSTRUCTOR, "(J)V" },
1991449Stomee 
200*6136Stomee 		/* java.math.BigInteger */
201*6136Stomee 		{ JCLASS,  &g_bigint_jc, "java/math/BigInteger" },
202*6136Stomee 		{ JMETHOD_STATIC, &g_bigint_val_jsm, "valueOf",
203*6136Stomee 			"(J)Ljava/math/BigInteger;" },
204*6136Stomee 		{ JMETHOD, &g_bigint_div_jm, "divide",
205*6136Stomee 			"(Ljava/math/BigInteger;)Ljava/math/BigInteger;" },
206*6136Stomee 		{ JMETHOD, &g_bigint_shl_jm, "shiftLeft",
207*6136Stomee 			"(I)Ljava/math/BigInteger;" },
208*6136Stomee 		{ JMETHOD, &g_bigint_or_jm, "or",
209*6136Stomee 			"(Ljava/math/BigInteger;)Ljava/math/BigInteger;" },
210*6136Stomee 		{ JMETHOD, &g_bigint_setbit_jm, "setBit",
211*6136Stomee 			"(I)Ljava/math/BigInteger;" },
212*6136Stomee 
2131449Stomee 		/* java.lang.String */
2141449Stomee 		{ JCLASS,  &g_string_jc, "java/lang/String" },
2151449Stomee 		{ JMETHOD, &g_strinit_bytes_jm, CONSTRUCTOR, "([B)V" },
2161449Stomee 		{ JMETHOD, &g_strbytes_jm, "getBytes", "()[B" },
2171449Stomee 		{ JMETHOD, &g_trim_jm, "trim", "()Ljava/lang/String;" },
2181449Stomee 
2193645Stomee 		/* java.lang.StringBuilder */
2203645Stomee 		{ JCLASS,  &g_buf_jc, "java/lang/StringBuilder" },
2211449Stomee 		{ JMETHOD, &g_bufinit_jm, CONSTRUCTOR, "()V" },
2221449Stomee 		{ JMETHOD, &g_buf_append_char_jm, "append",
2233645Stomee 			"(C)Ljava/lang/StringBuilder;" },
2241449Stomee 		{ JMETHOD, &g_buf_append_int_jm, "append",
2253645Stomee 			"(I)Ljava/lang/StringBuilder;" },
2261449Stomee 		{ JMETHOD, &g_buf_append_long_jm, "append",
2273645Stomee 			"(J)Ljava/lang/StringBuilder;" },
2281449Stomee 		{ JMETHOD, &g_buf_append_str_jm, "append",
2293645Stomee 			"(Ljava/lang/String;)Ljava/lang/StringBuilder;" },
2301449Stomee 		{ JMETHOD, &g_buf_append_obj_jm, "append",
2313645Stomee 			"(Ljava/lang/Object;)Ljava/lang/StringBuilder;" },
2321449Stomee 		{ JMETHOD, &g_buflen_jm, "length", "()I" },
2331449Stomee 		{ JMETHOD, &g_bufsetlen_jm, "setLength", "(I)V" },
2341449Stomee 
2351449Stomee 		/* java.lang.Object */
2361449Stomee 		{ JCLASS,  &g_object_jc, "java/lang/Object" },
2371449Stomee 		{ JMETHOD, &g_tostring_jm, "toString",
2381449Stomee 			"()Ljava/lang/String;" },
2391449Stomee 		{ JMETHOD, &g_equals_jm, "equals",
2401449Stomee 			"(Ljava/lang/Object;)Z" },
2411449Stomee 
2421449Stomee 		/* java.lang.Enum */
2431449Stomee 		{ JCLASS,  &g_enum_jc, "java/lang/Enum" },
2441449Stomee 		{ JMETHOD, &g_enumname_jm, "name",
2451449Stomee 			"()Ljava/lang/String;" },
2461449Stomee 
2471449Stomee 		/* List */
2481449Stomee 		{ JCLASS, &g_list_jc, "java/util/List" },
2491449Stomee 		{ JMETHOD, &g_listclear_jm, "clear", "()V" },
2501449Stomee 		{ JMETHOD, &g_listadd_jm, "add", "(Ljava/lang/Object;)Z" },
2511449Stomee 		{ JMETHOD, &g_listget_jm, "get", "(I)Ljava/lang/Object;" },
2521449Stomee 		{ JMETHOD, &g_listsize_jm, "size", "()I" },
2531449Stomee 
2541449Stomee 		{ DTJ_TYPE_END }
2551449Stomee 	};
2561449Stomee 
2571449Stomee 	status = dtj_cache_jni_classes(jenv, table);
2581449Stomee 	if (status == DTJ_OK) {
2591449Stomee 		g_dtj_load_common = B_TRUE;
2601449Stomee 	}
2611449Stomee 	return (status);
2621449Stomee }
2631449Stomee 
2641449Stomee static int
2651449Stomee /* ARGSUSED */
dtj_java_class_cmp(const void * v1,const void * v2,void * arg)2661449Stomee dtj_java_class_cmp(const void * v1, const void * v2, void *arg)
2671449Stomee {
2681449Stomee 	const dtj_java_class_t *c1 = v1;
2691449Stomee 	const dtj_java_class_t *c2 = v2;
2701449Stomee 	return (strcmp(c1->djc_name, c2->djc_name));
2711449Stomee }
2721449Stomee 
2731449Stomee static int
2741449Stomee /* ARGSUSED */
dtj_java_method_cmp(const void * v1,const void * v2,void * arg)2751449Stomee dtj_java_method_cmp(const void *v1, const void *v2, void *arg)
2761449Stomee {
2771449Stomee 	int cmp;
2781449Stomee 	const dtj_java_method_t *m1 = v1;
2791449Stomee 	const dtj_java_method_t *m2 = v2;
2801449Stomee 	cmp = strcmp(m1->djm_name, m2->djm_name);
2811449Stomee 	if (cmp == 0) {
2821449Stomee 		cmp = strcmp(m1->djm_signature, m2->djm_signature);
2831449Stomee 	}
2841449Stomee 	return (cmp);
2851449Stomee }
2861449Stomee 
2871449Stomee static int
2881449Stomee /* ARGSUSED */
dtj_java_field_cmp(const void * v1,const void * v2,void * arg)2891449Stomee dtj_java_field_cmp(const void *v1, const void *v2, void *arg)
2901449Stomee {
2911449Stomee 	const dtj_java_field_t *f1 = v1;
2921449Stomee 	const dtj_java_field_t *f2 = v2;
2931449Stomee 	return (strcmp(f1->djf_name, f2->djf_name));
2941449Stomee }
2951449Stomee 
2961449Stomee static dtj_java_class_t *
dtj_java_class_create(JNIEnv * jenv,jclass * jc,char * name,uu_list_pool_t * classpool,uu_list_pool_t * methodpool,uu_list_pool_t * fieldpool)2971449Stomee dtj_java_class_create(JNIEnv *jenv, jclass *jc, char *name,
2981449Stomee     uu_list_pool_t *classpool, uu_list_pool_t *methodpool,
2991449Stomee     uu_list_pool_t *fieldpool)
3001449Stomee {
3011449Stomee 	dtj_java_class_t *c = uu_zalloc(sizeof (dtj_java_class_t));
3021449Stomee 	if (c) {
3031449Stomee 		uu_list_node_init(c, &c->djc_node, classpool);
3041449Stomee 		c->djc_ptr = jc;
3051449Stomee 		c->djc_name = name;
3061449Stomee 		c->djc_methods = uu_list_create(methodpool, NULL,
3071449Stomee 		    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
3081449Stomee 		if (!c->djc_methods) {
3091449Stomee 			dtj_throw_out_of_memory(jenv,
3101449Stomee 			    "Failed method list creation");
3111449Stomee 			uu_list_node_fini(c, &c->djc_node, classpool);
3121449Stomee 			free(c);
3131449Stomee 			c = NULL;
3141449Stomee 		}
3151449Stomee 		c->djc_fields = uu_list_create(fieldpool, NULL,
3161449Stomee 		    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
3171449Stomee 		if (!c->djc_fields) {
3181449Stomee 			dtj_throw_out_of_memory(jenv,
3191449Stomee 			    "Failed field list creation");
3201449Stomee 			uu_list_destroy(c->djc_methods);
3211449Stomee 			c->djc_methods = NULL;
3221449Stomee 			uu_list_node_fini(c, &c->djc_node, classpool);
3231449Stomee 			free(c);
3241449Stomee 			c = NULL;
3251449Stomee 		}
3261449Stomee 	} else {
3271449Stomee 		dtj_throw_out_of_memory(jenv,
3281449Stomee 		    "Failed to allocate class description");
3291449Stomee 	}
3301449Stomee 	return (c);
3311449Stomee }
3321449Stomee 
3331449Stomee static dtj_java_method_t *
dtj_java_method_create(JNIEnv * jenv,jmethodID * jm,char * name,char * signature,uu_list_pool_t * methodpool)3341449Stomee dtj_java_method_create(JNIEnv *jenv, jmethodID *jm, char *name, char *signature,
3351449Stomee     uu_list_pool_t *methodpool)
3361449Stomee {
3371449Stomee 	dtj_java_method_t *m = uu_zalloc(sizeof (dtj_java_method_t));
3381449Stomee 	if (m) {
3391449Stomee 		uu_list_node_init(m, &m->djm_node, methodpool);
3401449Stomee 		m->djm_ptr = jm;
3411449Stomee 		m->djm_name = name;
3421449Stomee 		m->djm_signature = signature;
3431449Stomee 		m->djm_static = B_FALSE;
3441449Stomee 	} else {
3451449Stomee 		dtj_throw_out_of_memory(jenv,
3461449Stomee 		    "Failed to allocate method description");
3471449Stomee 	}
3481449Stomee 	return (m);
3491449Stomee }
3501449Stomee 
3511449Stomee static dtj_java_method_t *
dtj_java_static_method_create(JNIEnv * jenv,jmethodID * jm,char * name,char * signature,uu_list_pool_t * methodpool)3521449Stomee dtj_java_static_method_create(JNIEnv *jenv, jmethodID *jm, char *name,
3531449Stomee     char *signature, uu_list_pool_t *methodpool)
3541449Stomee {
3551449Stomee 	dtj_java_method_t *m = dtj_java_method_create(jenv, jm, name, signature,
3561449Stomee 	    methodpool);
3571449Stomee 	if (m) {
3581449Stomee 		m->djm_static = B_TRUE;
3591449Stomee 	}
3601449Stomee 	return (m);
3611449Stomee }
3621449Stomee 
3631449Stomee static dtj_java_field_t *
dtj_java_field_create(JNIEnv * jenv,jfieldID * jf,char * name,char * type,uu_list_pool_t * fieldpool)3641449Stomee dtj_java_field_create(JNIEnv *jenv, jfieldID *jf, char *name, char *type,
3651449Stomee     uu_list_pool_t *fieldpool)
3661449Stomee {
3671449Stomee 	dtj_java_field_t *f = uu_zalloc(sizeof (dtj_java_field_t));
3681449Stomee 	if (f) {
3691449Stomee 		uu_list_node_init(f, &f->djf_node, fieldpool);
3701449Stomee 		f->djf_ptr = jf;
3711449Stomee 		f->djf_name = name;
3721449Stomee 		f->djf_type = type;
3731449Stomee 		f->djf_static = B_FALSE;
3741449Stomee 	} else {
3751449Stomee 		dtj_throw_out_of_memory(jenv,
3761449Stomee 		    "Failed to allocate field description");
3771449Stomee 	}
3781449Stomee 	return (f);
3791449Stomee }
3801449Stomee 
3811449Stomee static dtj_java_field_t *
dtj_java_static_field_create(JNIEnv * jenv,jfieldID * jf,char * name,char * type,uu_list_pool_t * fieldpool)3821449Stomee dtj_java_static_field_create(JNIEnv *jenv, jfieldID *jf, char *name, char *type,
3831449Stomee     uu_list_pool_t *fieldpool)
3841449Stomee {
3851449Stomee 	dtj_java_field_t *f = dtj_java_field_create(jenv, jf, name, type,
3861449Stomee 	    fieldpool);
3871449Stomee 	if (f) {
3881449Stomee 		f->djf_static = B_TRUE;
3891449Stomee 	}
3901449Stomee 	return (f);
3911449Stomee }
3921449Stomee 
3931449Stomee static void
3941449Stomee /* ARGSUSED */
dtj_java_class_destroy(void * v,void * arg)3951449Stomee dtj_java_class_destroy(void *v, void *arg)
3961449Stomee {
3971449Stomee 	if (v) {
3981449Stomee 		dtj_java_class_t *c = v;
3991449Stomee 		c->djc_ptr = NULL;  /* do not free user-defined storage */
4001449Stomee 		c->djc_name = NULL; /* string literal */
4011449Stomee 		dtj_list_destroy(c->djc_methods, dtj_java_method_destroy, NULL);
4021449Stomee 		dtj_list_destroy(c->djc_fields, dtj_java_field_destroy, NULL);
4031449Stomee 		c->djc_methods = NULL;
4041449Stomee 		c->djc_fields = NULL;
4051449Stomee 		uu_free(v);
4061449Stomee 	}
4071449Stomee }
4081449Stomee 
4091449Stomee static void
4101449Stomee /* ARGSUSED */
dtj_java_method_destroy(void * v,void * arg)4111449Stomee dtj_java_method_destroy(void *v, void *arg)
4121449Stomee {
4131449Stomee 	if (v) {
4141449Stomee 		dtj_java_method_t *m = v;
4151449Stomee 		m->djm_ptr = NULL;	/* do not free user-defined space */
4161449Stomee 		m->djm_name = NULL;	/* string literal */
4171449Stomee 		m->djm_signature = NULL;	/* string literal */
4181449Stomee 		uu_free(v);
4191449Stomee 	}
4201449Stomee }
4211449Stomee 
4221449Stomee static void
4231449Stomee /* ARGSUSED */
dtj_java_field_destroy(void * v,void * arg)4241449Stomee dtj_java_field_destroy(void *v, void *arg)
4251449Stomee {
4261449Stomee 	if (v) {
4271449Stomee 		dtj_java_field_t *f = v;
4281449Stomee 		f->djf_ptr = NULL;  /* do not free user-defined space */
4291449Stomee 		f->djf_name = NULL; /* string literal */
4301449Stomee 		f->djf_type = NULL; /* string literal */
4311449Stomee 		uu_free(f);
4321449Stomee 	}
4331449Stomee }
4341449Stomee 
4351449Stomee dtj_status_t
dtj_cache_jni_classes(JNIEnv * jenv,const dtj_table_entry_t * table)4361449Stomee dtj_cache_jni_classes(JNIEnv *jenv, const dtj_table_entry_t *table)
4371449Stomee {
4381449Stomee 	dtj_java_class_t *class;
4391449Stomee 	uu_list_pool_t *classpool;
4401449Stomee 	uu_list_pool_t *methodpool;
4411449Stomee 	uu_list_pool_t *fieldpool;
4421449Stomee 	uu_list_t *classes;
4431449Stomee 	uu_list_walk_t *itr;
4441449Stomee 	jclass jc;
4451449Stomee 	jclass gjc;
4461449Stomee 	dtj_status_t status;
4471449Stomee 
4481449Stomee 	classpool = uu_list_pool_create("classpool",
4491449Stomee 	    sizeof (dtj_java_class_t),
4501449Stomee 	    offsetof(dtj_java_class_t, djc_node), dtj_java_class_cmp,
4511449Stomee 	    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
4521449Stomee 	if (!classpool) {
4531449Stomee 		dtj_throw_out_of_memory(jenv, "failed class pool creation");
4541449Stomee 		return (DTJ_ERR);
4551449Stomee 	}
4561449Stomee 	methodpool = uu_list_pool_create("methodpool",
4571449Stomee 	    sizeof (dtj_java_method_t),
4581449Stomee 	    offsetof(dtj_java_method_t, djm_node), dtj_java_method_cmp,
4591449Stomee 	    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
4601449Stomee 	if (!methodpool) {
4611449Stomee 		dtj_throw_out_of_memory(jenv, "failed method pool creation");
4621449Stomee 		return (DTJ_ERR);
4631449Stomee 	}
4641449Stomee 	fieldpool = uu_list_pool_create("fieldpool",
4651449Stomee 	    sizeof (dtj_java_field_t),
4661449Stomee 	    offsetof(dtj_java_field_t, djf_node), dtj_java_field_cmp,
4671449Stomee 	    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
4681449Stomee 	if (!fieldpool) {
4691449Stomee 		dtj_throw_out_of_memory(jenv, "failed field pool creation");
4701449Stomee 		return (DTJ_ERR);
4711449Stomee 	}
4721449Stomee 
4731449Stomee 	classes = uu_list_create(classpool, NULL,
4741449Stomee 	    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
4751449Stomee 	if (!classes) {
4761449Stomee 		dtj_throw_out_of_memory(jenv, "failed class list creation");
4771449Stomee 		return (DTJ_ERR);
4781449Stomee 	}
4791449Stomee 
4801449Stomee 	status = dtj_get_jni_classes(jenv, classes, classpool, methodpool,
4811449Stomee 	    fieldpool, table);
4821449Stomee 	if (status != DTJ_OK) {
4831449Stomee 		/* java error pending */
4841449Stomee 		return (status);
4851449Stomee 	}
4861449Stomee 
4871449Stomee 	itr = uu_list_walk_start(classes, 0);
4881449Stomee 	while ((class = uu_list_walk_next(itr)) != NULL) {
4891449Stomee 		jc = (*jenv)->FindClass(jenv, class->djc_name);
4901449Stomee 		if (!jc) {
4911449Stomee 			/* NoClassDefFoundError pending */
4921449Stomee 			return (DTJ_ERR);
4931449Stomee 		}
4941449Stomee 		gjc = (*jenv)->NewGlobalRef(jenv, jc);
4951449Stomee 		(*jenv)->DeleteLocalRef(jenv, jc);
4961449Stomee 		if (!gjc) {
4971449Stomee 			dtj_throw_out_of_memory(jenv,
4981449Stomee 			    "Failed to create global class reference");
4991449Stomee 			return (DTJ_ERR);
5001449Stomee 		}
5011449Stomee 		*(class->djc_ptr) = gjc;
5021449Stomee 		status = dtj_cache_jni_methods(jenv, class);
5031449Stomee 		if (status != DTJ_OK) {
5041449Stomee 			/* java error pending */
5051449Stomee 			return (status);
5061449Stomee 		}
5071449Stomee 		status = dtj_cache_jni_fields(jenv, class);
5081449Stomee 		if (status != DTJ_OK) {
5091449Stomee 			/* java error pending */
5101449Stomee 			return (status);
5111449Stomee 		}
5121449Stomee 	}
5131449Stomee 	uu_list_walk_end(itr);
5141449Stomee 	dtj_list_destroy(classes, dtj_java_class_destroy, NULL);
5151449Stomee 	uu_list_pool_destroy(classpool);
5161449Stomee 	uu_list_pool_destroy(methodpool);
5171449Stomee 	uu_list_pool_destroy(fieldpool);
5181449Stomee 	return (DTJ_OK);
5191449Stomee }
5201449Stomee 
5211449Stomee /*
5221449Stomee  * Converts JNI table entry desriptions into java_class_t descriptors.
5231449Stomee  */
5241449Stomee static dtj_status_t
dtj_get_jni_classes(JNIEnv * jenv,uu_list_t * classes,uu_list_pool_t * classpool,uu_list_pool_t * methodpool,uu_list_pool_t * fieldpool,const dtj_table_entry_t * table)5251449Stomee dtj_get_jni_classes(JNIEnv *jenv, uu_list_t *classes,
5261449Stomee     uu_list_pool_t *classpool, uu_list_pool_t *methodpool,
5271449Stomee     uu_list_pool_t *fieldpool, const dtj_table_entry_t *table)
5281449Stomee {
5291449Stomee 	int i;
5301449Stomee 	dtj_java_class_t *c = NULL;
5311449Stomee 	dtj_java_method_t *m;
5321449Stomee 	dtj_java_field_t *f;
5331449Stomee 
5341449Stomee 	for (i = 0; table[i].djte_type != DTJ_TYPE_END; ++i) {
5351449Stomee 		/*
5361449Stomee 		 * Class not added until all of its method and field information
5371449Stomee 		 * is attached, so we defer adding a class until the next
5381449Stomee 		 * element with type JCLASS.
5391449Stomee 		 */
5401449Stomee 		switch (table[i].djte_type) {
5411449Stomee 		case JCLASS:
5421449Stomee 			if (c) {
5431449Stomee 				/* previous class */
5441449Stomee 				if (!dtj_list_add(classes, c)) {
5451449Stomee 					dtj_throw_out_of_memory(jenv,
5461449Stomee 					    "Failed to add class description");
5471449Stomee 					/*
5481449Stomee 					 * In response to an error return value,
5491449Stomee 					 * the caller will delete the class
5501449Stomee 					 * descriptions list with any
5511449Stomee 					 * descriptions created so far.
5521449Stomee 					 */
5531449Stomee 					return (DTJ_ERR);
5541449Stomee 				}
5551449Stomee 			}
5561449Stomee 			c = dtj_java_class_create(jenv,
5571449Stomee 			    (jclass *)table[i].djte_addr, table[i].djte_name,
5581449Stomee 			    classpool, methodpool, fieldpool);
5591449Stomee 			if (!c) {
5601449Stomee 				/* OutOfMemoryError pending */
5611449Stomee 				return (DTJ_ERR);
5621449Stomee 			}
5631449Stomee 			break;
5641449Stomee 		case JMETHOD:
5651449Stomee 			if (!c) {
5661449Stomee 				dtj_throw_illegal_state(jenv,
5671449Stomee 				    "method description not preceded "
5681449Stomee 				    "by class description");
5691449Stomee 				return (DTJ_ERR);
5701449Stomee 			}
5711449Stomee 			m = dtj_java_method_create(jenv,
5721449Stomee 			    (jmethodID *)table[i].djte_addr,
5731449Stomee 			    table[i].djte_name, table[i].djte_desc,
5741449Stomee 			    methodpool);
5751449Stomee 			if (!m) {
5761449Stomee 				/* OutOfMemoryError pending */
5771449Stomee 				return (DTJ_ERR);
5781449Stomee 			}
5791449Stomee 			if (!dtj_list_add(c->djc_methods, m)) {
5801449Stomee 				dtj_throw_out_of_memory(jenv,
5811449Stomee 				    "Failed to add method description");
5821449Stomee 				return (DTJ_ERR);
5831449Stomee 			}
5841449Stomee 			break;
5851449Stomee 		case JMETHOD_STATIC:
5861449Stomee 			if (!c) {
5871449Stomee 				dtj_throw_illegal_state(jenv,
5881449Stomee 				    "static method description not preceded "
5891449Stomee 				    "by class description");
5901449Stomee 				return (DTJ_ERR);
5911449Stomee 			}
5921449Stomee 			m = dtj_java_static_method_create(jenv,
5931449Stomee 			    (jmethodID *)table[i].djte_addr,
5941449Stomee 			    table[i].djte_name, table[i].djte_desc,
5951449Stomee 			    methodpool);
5961449Stomee 			if (!m) {
5971449Stomee 				/* OutOfMemoryError pending */
5981449Stomee 				return (DTJ_ERR);
5991449Stomee 			}
6001449Stomee 			if (!dtj_list_add(c->djc_methods, m)) {
6011449Stomee 				dtj_throw_out_of_memory(jenv,
6021449Stomee 				    "Failed to add static method description");
6031449Stomee 				return (DTJ_ERR);
6041449Stomee 			}
6051449Stomee 			break;
6061449Stomee 		case JFIELD:
6071449Stomee 			if (!c) {
6081449Stomee 				dtj_throw_illegal_state(jenv,
6091449Stomee 				    "field description not preceded "
6101449Stomee 				    "by class description");
6111449Stomee 				return (DTJ_ERR);
6121449Stomee 			}
6131449Stomee 			f = dtj_java_field_create(jenv,
6141449Stomee 			    (jfieldID *)table[i].djte_addr,
6151449Stomee 			    table[i].djte_name, table[i].djte_desc,
6161449Stomee 			    fieldpool);
6171449Stomee 			if (!f) {
6181449Stomee 				/* OutOfMemoryError pending */
6191449Stomee 				return (DTJ_ERR);
6201449Stomee 			}
6211449Stomee 			if (!dtj_list_add(c->djc_fields, f)) {
6221449Stomee 				dtj_throw_out_of_memory(jenv,
6231449Stomee 				    "Failed to add field description");
6241449Stomee 				return (DTJ_ERR);
6251449Stomee 			}
6261449Stomee 			break;
6271449Stomee 		case JFIELD_STATIC:
6281449Stomee 			if (!c) {
6291449Stomee 				dtj_throw_illegal_state(jenv,
6301449Stomee 				    "static field description not preceded "
6311449Stomee 				    "by class description");
6321449Stomee 				return (DTJ_ERR);
6331449Stomee 			}
6341449Stomee 			f = dtj_java_static_field_create(jenv,
6351449Stomee 			    (jfieldID *)table[i].djte_addr,
6361449Stomee 			    table[i].djte_name, table[i].djte_desc,
6371449Stomee 			    fieldpool);
6381449Stomee 			if (!f) {
6391449Stomee 				/* OutOfMemoryError pending */
6401449Stomee 				return (DTJ_ERR);
6411449Stomee 			}
6421449Stomee 			if (!dtj_list_add(c->djc_fields, f)) {
6431449Stomee 				dtj_throw_out_of_memory(jenv,
6441449Stomee 				    "Failed to add static field description");
6451449Stomee 				return (DTJ_ERR);
6461449Stomee 			}
6471449Stomee 			break;
6481449Stomee 		default:
6491449Stomee 			dtj_throw_illegal_state(jenv,
6501449Stomee 			    "Unexpected jni_type_e: %d", table[i].djte_type);
6511449Stomee 			return (DTJ_ERR);
6521449Stomee 		}
6531449Stomee 	}
6541449Stomee 	if (c) {
6551449Stomee 		/* last class */
6561449Stomee 		if (!dtj_list_add(classes, c)) {
6571449Stomee 			dtj_throw_out_of_memory(jenv,
6581449Stomee 			    "Failed to add class description");
6591449Stomee 			return (DTJ_ERR);
6601449Stomee 		}
6611449Stomee 	}
6621449Stomee 
6631449Stomee 	return (DTJ_OK);
6641449Stomee }
6651449Stomee 
6661449Stomee static dtj_status_t
dtj_cache_jni_methods(JNIEnv * jenv,dtj_java_class_t * c)6671449Stomee dtj_cache_jni_methods(JNIEnv *jenv, dtj_java_class_t *c)
6681449Stomee {
6691449Stomee 	dtj_java_method_t *method;
6701449Stomee 	jmethodID jm;
6711449Stomee 	uu_list_walk_t *itr;
6721449Stomee 	itr = uu_list_walk_start(c->djc_methods, 0);
6731449Stomee 	while ((method = uu_list_walk_next(itr)) != NULL) {
6741449Stomee 		if (method->djm_static) {
6751449Stomee 			jm = (*jenv)->GetStaticMethodID(jenv, *(c->djc_ptr),
6761449Stomee 			    method->djm_name, method->djm_signature);
6771449Stomee 		} else {
6781449Stomee 			jm = (*jenv)->GetMethodID(jenv, *(c->djc_ptr),
6791449Stomee 			    method->djm_name, method->djm_signature);
6801449Stomee 		}
6811449Stomee 		if (jm == 0) {
6821449Stomee 			/*
6831449Stomee 			 * The pending NoSuchMethodError gives only the
6841449Stomee 			 * method name, which is not so helpful for
6851449Stomee 			 * overloaded methods and methods such as <init>
6861449Stomee 			 * that have the same name in multiple classes.
6871449Stomee 			 * Clear the pending error and throw one that
6881449Stomee 			 * includes the class name and the method
6891449Stomee 			 * signature.
6901449Stomee 			 */
6911449Stomee 			jclass jc;
6921449Stomee 			char msg[DTJ_MSG_SIZE];
6931449Stomee 			(*jenv)->ExceptionClear(jenv);
6941449Stomee 			(void) snprintf(msg, sizeof (msg), "%s %s %s",
6951449Stomee 			    c->djc_name, method->djm_name,
6961449Stomee 			    method->djm_signature);
6971449Stomee 
6981449Stomee 			jc = (*jenv)->FindClass(jenv,
6991449Stomee 			    "java/lang/NoSuchMethodError");
7001449Stomee 			(*jenv)->ThrowNew(jenv, jc, msg);
7011449Stomee 			(*jenv)->DeleteLocalRef(jenv, jc);
7021449Stomee 			return (DTJ_ERR);
7031449Stomee 		}
7041449Stomee 		*(method->djm_ptr) = jm;
7051449Stomee 	}
7061449Stomee 	uu_list_walk_end(itr);
7071449Stomee 	return (DTJ_OK);
7081449Stomee }
7091449Stomee 
7101449Stomee static dtj_status_t
dtj_cache_jni_fields(JNIEnv * jenv,dtj_java_class_t * c)7111449Stomee dtj_cache_jni_fields(JNIEnv *jenv, dtj_java_class_t *c)
7121449Stomee {
7131449Stomee 	dtj_java_field_t *field;
7141449Stomee 	jfieldID jf;
7151449Stomee 	uu_list_walk_t *itr;
7161449Stomee 	itr = uu_list_walk_start(c->djc_fields, 0);
7171449Stomee 	while ((field = uu_list_walk_next(itr)) != NULL) {
7181449Stomee 		if (field->djf_static) {
7191449Stomee 			jf = (*jenv)->GetStaticFieldID(jenv, *(c->djc_ptr),
7201449Stomee 			    field->djf_name, field->djf_type);
7211449Stomee 		} else {
7221449Stomee 			jf = (*jenv)->GetFieldID(jenv, *(c->djc_ptr),
7231449Stomee 			    field->djf_name, field->djf_type);
7241449Stomee 		}
7251449Stomee 		if (jf == 0) {
7261449Stomee 			jclass jc;
7271449Stomee 			char msg[DTJ_MSG_SIZE];
7281449Stomee 			(*jenv)->ExceptionClear(jenv);
7291449Stomee 			(void) snprintf(msg, sizeof (msg),
7301449Stomee 			    "%s.%s signature: %s", c->djc_name,
7311449Stomee 			    field->djf_name, field->djf_type);
7321449Stomee 
7331449Stomee 			jc = (*jenv)->FindClass(jenv,
7341449Stomee 			    "java/lang/NoSuchFieldError");
7351449Stomee 			(*jenv)->ThrowNew(jenv, jc, msg);
7361449Stomee 			(*jenv)->DeleteLocalRef(jenv, jc);
7371449Stomee 			return (DTJ_ERR);
7381449Stomee 		}
7391449Stomee 		*(field->djf_ptr) = jf;
7401449Stomee 	}
7411449Stomee 	uu_list_walk_end(itr);
7421449Stomee 	return (DTJ_OK);
7431449Stomee }
7441449Stomee 
7451449Stomee 
7461449Stomee /* Common utilities */
7471449Stomee 
7481449Stomee static void
dtj_throw(JNIEnv * jenv,jclass jc,const char * fmt,va_list * ap)7491449Stomee dtj_throw(JNIEnv *jenv, jclass jc, const char *fmt, va_list *ap)
7501449Stomee {
7511449Stomee 	char msg[DTJ_MSG_SIZE];
7521449Stomee 	(void) vsnprintf(msg, sizeof (msg), fmt, *ap);
7531449Stomee 	(*jenv)->ThrowNew(jenv, jc, msg);
7541449Stomee }
7551449Stomee 
7561449Stomee void
dtj_throw_out_of_memory(JNIEnv * jenv,const char * fmt,...)7571449Stomee dtj_throw_out_of_memory(JNIEnv *jenv, const char *fmt, ...)
7581449Stomee {
7591449Stomee 	va_list ap;
7601449Stomee 	jclass jc;
7611449Stomee 	/*
7621449Stomee 	 * JNI documentation unclear whether NewGlobalRef() can throw
7631449Stomee 	 * OutOfMemoryError, so we'll make this function safe in case
7641449Stomee 	 * OutOfMemoryError has already been thrown
7651449Stomee 	 */
7661449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
7671449Stomee 		return;
7681449Stomee 	}
7691449Stomee 	jc = (*jenv)->FindClass(jenv,
7701449Stomee 	    "java/lang/OutOfMemoryError");
7711449Stomee 	va_start(ap, fmt);
7721449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
7731449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
7741449Stomee 	va_end(ap);
7751449Stomee }
7761449Stomee 
7771449Stomee void
dtj_throw_null_pointer(JNIEnv * jenv,const char * fmt,...)7781449Stomee dtj_throw_null_pointer(JNIEnv *jenv, const char *fmt, ...)
7791449Stomee {
7801449Stomee 	va_list ap;
7811449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
7821449Stomee 	    "java/lang/NullPointerException");
7831449Stomee 	va_start(ap, fmt);
7841449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
7851449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
7861449Stomee 	va_end(ap);
7871449Stomee }
7881449Stomee 
7891449Stomee void
dtj_throw_illegal_state(JNIEnv * jenv,const char * fmt,...)7901449Stomee dtj_throw_illegal_state(JNIEnv *jenv, const char *fmt, ...)
7911449Stomee {
7921449Stomee 	va_list ap;
7931449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
7941449Stomee 	    "java/lang/IllegalStateException");
7951449Stomee 	va_start(ap, fmt);
7961449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
7971449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
7981449Stomee 	va_end(ap);
7991449Stomee }
8001449Stomee 
8011449Stomee void
dtj_throw_illegal_argument(JNIEnv * jenv,const char * fmt,...)8021449Stomee dtj_throw_illegal_argument(JNIEnv *jenv, const char *fmt, ...)
8031449Stomee {
8041449Stomee 	va_list ap;
8051449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
8061449Stomee 	    "java/lang/IllegalArgumentException");
8071449Stomee 	va_start(ap, fmt);
8081449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
8091449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
8101449Stomee 	va_end(ap);
8111449Stomee }
8121449Stomee 
8131449Stomee void
dtj_throw_no_such_element(JNIEnv * jenv,const char * fmt,...)8141449Stomee dtj_throw_no_such_element(JNIEnv *jenv, const char *fmt, ...)
8151449Stomee {
8161449Stomee 	va_list ap;
8171449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
8181449Stomee 	    "java/util/NoSuchElementException");
8191449Stomee 	va_start(ap, fmt);
8201449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
8211449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
8221449Stomee 	va_end(ap);
8231449Stomee }
8241449Stomee 
8251449Stomee void
dtj_throw_class_cast(JNIEnv * jenv,const char * fmt,...)8261449Stomee dtj_throw_class_cast(JNIEnv *jenv, const char *fmt, ...)
8271449Stomee {
8281449Stomee 	va_list ap;
8291449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
8301449Stomee 	    "java/lang/ClassCastException");
8311449Stomee 	va_start(ap, fmt);
8321449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
8331449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
8341449Stomee 	va_end(ap);
8351449Stomee }
8361449Stomee 
8371449Stomee void
dtj_throw_assertion(JNIEnv * jenv,const char * fmt,...)8381449Stomee dtj_throw_assertion(JNIEnv *jenv, const char *fmt, ...)
8391449Stomee {
8401449Stomee 	va_list ap;
8411449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
8421449Stomee 	    "java/lang/AssertionError");
8431449Stomee 	va_start(ap, fmt);
8441449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
8451449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
8461449Stomee 	va_end(ap);
8471449Stomee }
8481449Stomee 
8491449Stomee void
dtj_throw_resource_limit(JNIEnv * jenv,const char * fmt,...)8501449Stomee dtj_throw_resource_limit(JNIEnv *jenv, const char *fmt, ...)
8511449Stomee {
8521449Stomee 	va_list ap;
8531449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
8541449Stomee 	    "org/opensolaris/os/dtrace/ResourceLimitException");
8551449Stomee 	va_start(ap, fmt);
8561449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
8571449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
8581449Stomee 	va_end(ap);
8591449Stomee }
8601449Stomee 
8611449Stomee void
dtj_wrap_exception(JNIEnv * jenv,const char * file,int line)8621449Stomee dtj_wrap_exception(JNIEnv *jenv, const char *file, int line)
8631449Stomee {
8641449Stomee 	jthrowable e = NULL;
8651449Stomee 	jthrowable nx = NULL;
8661449Stomee 	jstring jfile = NULL;
8671449Stomee 
8681449Stomee 	e = (*jenv)->ExceptionOccurred(jenv);
8691449Stomee 	if (!e) {
8701449Stomee 		return;
8711449Stomee 	}
8721449Stomee 
8731449Stomee 	if (!g_dtj_load_common) {
8741449Stomee 		return;
8751449Stomee 	}
8761449Stomee 
8771449Stomee 	(*jenv)->ExceptionClear(jenv);
8781449Stomee 
8791449Stomee 	/* Unsafe to test while exception pending */
8801449Stomee 	if ((*jenv)->IsInstanceOf(jenv, e, g_nx_jc)) {
8811449Stomee 		/* Already wrapped */
8821449Stomee 		(*jenv)->Throw(jenv, e);
8831449Stomee 		(*jenv)->DeleteLocalRef(jenv, e);
8841449Stomee 		return;
8851449Stomee 	}
8861449Stomee 
8871449Stomee 	jfile = dtj_NewStringNative(jenv, file);
8881449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
8891449Stomee 		/*
8901449Stomee 		 * Only wrap the exception if possible, otherwise just throw the
8911449Stomee 		 * original exception.
8921449Stomee 		 */
8931449Stomee 		(*jenv)->ExceptionClear(jenv);
8941449Stomee 		(*jenv)->Throw(jenv, e);
8951449Stomee 		(*jenv)->DeleteLocalRef(jenv, e);
8961449Stomee 		return;
8971449Stomee 	}
8981449Stomee 
8991449Stomee 	nx = (jthrowable)(*jenv)->NewObject(jenv, g_nx_jc, g_nxinit_jm,
9001449Stomee 	    jfile, line, e);
9011449Stomee 	(*jenv)->DeleteLocalRef(jenv, jfile);
9021449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
9031449Stomee 		(*jenv)->ExceptionClear(jenv);
9041449Stomee 		(*jenv)->Throw(jenv, e);
9051449Stomee 		(*jenv)->DeleteLocalRef(jenv, e);
9061449Stomee 		return;
9071449Stomee 	}
9081449Stomee 
9091449Stomee 	(*jenv)->DeleteLocalRef(jenv, e);
9101449Stomee 	(*jenv)->Throw(jenv, nx);
9111449Stomee 	(*jenv)->DeleteLocalRef(jenv, nx);
9121449Stomee }
9131449Stomee 
9141449Stomee /*
9151449Stomee  * Calls the given java object's toString() method and prints the value to
9161449Stomee  * stdout.  Useful for debugging.  Guaranteed that no exception is pending when
9171449Stomee  * this function returns.
9181449Stomee  */
9191449Stomee void
dtj_print_object(JNIEnv * jenv,jobject jobj)9201449Stomee dtj_print_object(JNIEnv *jenv, jobject jobj)
9211449Stomee {
9221449Stomee 	jstring jstr;
9231449Stomee 	const char *cstr;
9241449Stomee 
9251449Stomee 	if (!g_dtj_load_common) {
9261449Stomee 		dtj_throw_illegal_state(jenv,
9271449Stomee 		    "dtj_load_common() has not been called");
9281449Stomee 		(*jenv)->ExceptionDescribe(jenv); /* clears the exception */
9291449Stomee 		return;
9301449Stomee 	}
9311449Stomee 
9321449Stomee 	if (!jobj) {
9331449Stomee 		(void) printf("null\n");
9341449Stomee 		return;
9351449Stomee 	}
9361449Stomee 
9371449Stomee 	jstr = (*jenv)->CallObjectMethod(jenv, jobj, g_tostring_jm);
9381449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
9391449Stomee 		(*jenv)->ExceptionDescribe(jenv); /* clears the exception */
9401449Stomee 		return;
9411449Stomee 	}
9421449Stomee 	cstr = (*jenv)->GetStringUTFChars(jenv, jstr, 0);
9431449Stomee 	if (cstr) {
9441449Stomee 		(void) printf("%s\n", cstr);
9451449Stomee 	} else {
9461449Stomee 		(*jenv)->ExceptionDescribe(jenv); /* clears the exception */
9471449Stomee 		(*jenv)->DeleteLocalRef(jenv, jstr);
9481449Stomee 		return;
9491449Stomee 	}
9501449Stomee 	(*jenv)->ReleaseStringUTFChars(jenv, jstr, cstr);
9511449Stomee 	(*jenv)->DeleteLocalRef(jenv, jstr);
9521449Stomee }
9531449Stomee 
954*6136Stomee jobject
dtj_uint64(JNIEnv * jenv,uint64_t u)955*6136Stomee dtj_uint64(JNIEnv *jenv, uint64_t u)
956*6136Stomee {
957*6136Stomee 	int64_t i = (int64_t)u;
958*6136Stomee 	jobject val64;
959*6136Stomee 
960*6136Stomee 	if (i >= 0) {
961*6136Stomee 		val64 = (*jenv)->CallStaticObjectMethod(jenv, g_bigint_jc,
962*6136Stomee 		    g_bigint_val_jsm, u);
963*6136Stomee 	} else {
964*6136Stomee 		jobject tmp;
965*6136Stomee 
966*6136Stomee 		u ^= ((uint64_t)0x1 << 63);
967*6136Stomee 		val64 = (*jenv)->CallStaticObjectMethod(jenv, g_bigint_jc,
968*6136Stomee 		    g_bigint_val_jsm, u);
969*6136Stomee 		tmp = val64;
970*6136Stomee 		val64 = (*jenv)->CallObjectMethod(jenv, tmp,
971*6136Stomee 		    g_bigint_setbit_jm, 63);
972*6136Stomee 		(*jenv)->DeleteLocalRef(jenv, tmp);
973*6136Stomee 	}
974*6136Stomee 
975*6136Stomee 	return (val64);
976*6136Stomee }
977*6136Stomee 
978*6136Stomee jobject
dtj_int128(JNIEnv * jenv,uint64_t high,uint64_t low)979*6136Stomee dtj_int128(JNIEnv *jenv, uint64_t high, uint64_t low)
980*6136Stomee {
981*6136Stomee 	jobject val128;
982*6136Stomee 	jobject low64;
983*6136Stomee 	jobject tmp;
984*6136Stomee 
985*6136Stomee 	val128 = (*jenv)->CallStaticObjectMethod(jenv, g_bigint_jc,
986*6136Stomee 	    g_bigint_val_jsm, high);
987*6136Stomee 	tmp = val128;
988*6136Stomee 	val128 = (*jenv)->CallObjectMethod(jenv, tmp, g_bigint_shl_jm, 64);
989*6136Stomee 	(*jenv)->DeleteLocalRef(jenv, tmp);
990*6136Stomee 	low64 = dtj_uint64(jenv, low);
991*6136Stomee 	tmp = val128;
992*6136Stomee 	val128 = (*jenv)->CallObjectMethod(jenv, tmp, g_bigint_or_jm, low64);
993*6136Stomee 	(*jenv)->DeleteLocalRef(jenv, tmp);
994*6136Stomee 	(*jenv)->DeleteLocalRef(jenv, low64);
995*6136Stomee 
996*6136Stomee 	return (val128);
997*6136Stomee }
998*6136Stomee 
9991449Stomee jstring
dtj_format_string(JNIEnv * jenv,const char * fmt,...)10001449Stomee dtj_format_string(JNIEnv *jenv, const char *fmt, ...)
10011449Stomee {
10021449Stomee 	va_list ap;
10031449Stomee 	char str[DTJ_MSG_SIZE];
10041449Stomee 
10051449Stomee 	jstring jstr = NULL;
10061449Stomee 
10071449Stomee 	va_start(ap, fmt);
10081449Stomee 	(void) vsnprintf(str, sizeof (str), fmt, ap);
10091449Stomee 	va_end(ap);
10101449Stomee 
10111449Stomee 	jstr = dtj_NewStringNative(jenv, str);
10121449Stomee 	/* return NULL if OutOfMemoryError pending */
10131449Stomee 	return (jstr);
10141449Stomee }
10151449Stomee 
10161449Stomee jstring
dtj_NewStringNative(JNIEnv * jenv,const char * str)10171449Stomee dtj_NewStringNative(JNIEnv *jenv, const char *str)
10181449Stomee {
10191449Stomee 	jstring result;
10201449Stomee 	jbyteArray bytes = 0;
10211449Stomee 	int len;
10221449Stomee 
10231449Stomee 	if (!g_dtj_load_common) {
10241449Stomee 		dtj_throw_illegal_state(jenv,
10251449Stomee 		    "dtj_load_common() has not been called");
10261449Stomee 		return (NULL);
10271449Stomee 	}
10281449Stomee 
10291449Stomee 	len = strlen(str);
10301449Stomee 
10311449Stomee 	bytes = (*jenv)->NewByteArray(jenv, len);
10321449Stomee 	if (!bytes) {
10331449Stomee 		return (NULL); /* OutOfMemoryError pending */
10341449Stomee 	}
10351449Stomee 	(*jenv)->SetByteArrayRegion(jenv, bytes, 0, len,
10361449Stomee 	    (jbyte *)str);
10371449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
10381449Stomee 		(*jenv)->DeleteLocalRef(jenv, bytes);
10391449Stomee 		return (NULL); /* ArrayIndexOutOfBoundsException pending */
10401449Stomee 	}
10411449Stomee 	result = (*jenv)->NewObject(jenv, g_string_jc, g_strinit_bytes_jm,
10421449Stomee 	    bytes);
10431449Stomee 	(*jenv)->DeleteLocalRef(jenv, bytes);
10441449Stomee 	/* return NULL result if exception pending */
10451449Stomee 	return (result);
10461449Stomee }
10471449Stomee 
10481449Stomee char *
dtj_GetStringNativeChars(JNIEnv * jenv,jstring jstr)10491449Stomee dtj_GetStringNativeChars(JNIEnv *jenv, jstring jstr)
10501449Stomee {
10511449Stomee 	jbyteArray bytes = NULL;
10521449Stomee 
10531449Stomee 	jint len;
10541449Stomee 	char *result = NULL;
10551449Stomee 
10561449Stomee 	if (!g_dtj_load_common) {
10571449Stomee 		dtj_throw_illegal_state(jenv,
10581449Stomee 		    "dtj_load_common() has not been called");
10591449Stomee 		return (NULL);
10601449Stomee 	}
10611449Stomee 
10621449Stomee 	bytes = (*jenv)->CallObjectMethod(jenv, jstr, g_strbytes_jm);
10631449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
10641449Stomee 		return (NULL); /* OutOfMemoryError pending */
10651449Stomee 	}
10661449Stomee 	/* Does not throw exceptions */
10671449Stomee 	len = (*jenv)->GetArrayLength(jenv, bytes);
10681449Stomee 	result = malloc(len + 1);
10691449Stomee 	if (!result) {
10701449Stomee 		(*jenv)->DeleteLocalRef(jenv, bytes);
10711449Stomee 		dtj_throw_out_of_memory(jenv,
10721449Stomee 		    "could not allocate native chars");
10731449Stomee 		return (NULL);
10741449Stomee 	}
10751449Stomee 
10761449Stomee 	/* Skip check for ArrayIndexOutOfBoundsException */
10771449Stomee 	(*jenv)->GetByteArrayRegion(jenv, bytes, 0, len,
10781449Stomee 	    (jbyte *)result);
10791449Stomee 	(*jenv)->DeleteLocalRef(jenv, bytes);
10801449Stomee 	result[len] = '\0'; /* NUL-terminate */
10811449Stomee 
10821449Stomee 	return (result);
10831449Stomee }
10841449Stomee 
10851449Stomee void
10861449Stomee /* ARGSUSED */
dtj_ReleaseStringNativeChars(JNIEnv * jenv,jstring jstr,const char * str)10871449Stomee dtj_ReleaseStringNativeChars(JNIEnv *jenv, jstring jstr, const char *str)
10881449Stomee {
10891449Stomee 	free((void *)str);
10901449Stomee }
10911449Stomee 
10921449Stomee char **
dtj_get_argv(JNIEnv * jenv,jobjectArray args,int * argc)10931449Stomee dtj_get_argv(JNIEnv *jenv, jobjectArray args, int *argc)
10941449Stomee {
10951449Stomee 	char **argv = NULL; /* return value */
10961449Stomee 	const char *str;
10971449Stomee 	int i;
10981449Stomee 
10991449Stomee 	jstring jstr = NULL;
11001449Stomee 
11011449Stomee 	if (!g_dtj_load_common) {
11021449Stomee 		dtj_throw_illegal_state(jenv,
11031449Stomee 		    "dtj_load_common() has not been called");
11041449Stomee 		return (NULL);
11051449Stomee 	}
11061449Stomee 
11071449Stomee 	*argc = (*jenv)->GetArrayLength(jenv, args);
11081449Stomee 	/*
11091449Stomee 	 * Initialize all string pointers to NULL so that in case of an error
11101449Stomee 	 * filling in the array, free_argv() will not attempt to free the
11111449Stomee 	 * unallocated elements.  Also NULL-terminate the string array for
11121449Stomee 	 * functions that expect terminating NULL rather than rely on argc.
11131449Stomee 	 */
11141449Stomee 	argv = uu_zalloc((sizeof (char *)) * (*argc + 1));
11151449Stomee 	if (!argv) {
11161449Stomee 		dtj_throw_out_of_memory(jenv, "Failed to allocate args array");
11171449Stomee 		return (NULL);
11181449Stomee 	}
11191449Stomee 
11201449Stomee 	for (i = 0; i < *argc; ++i) {
11211449Stomee 		jstr = (*jenv)->GetObjectArrayElement(jenv, args, i);
11221449Stomee 		if ((*jenv)->ExceptionCheck(jenv)) {
11231449Stomee 			dtj_free_argv(argv);
11241449Stomee 			return (NULL);
11251449Stomee 		}
11261449Stomee 		str = dtj_GetStringNativeChars(jenv, jstr);
11271449Stomee 		if ((*jenv)->ExceptionCheck(jenv)) {
11281449Stomee 			dtj_free_argv(argv);
11291449Stomee 			(*jenv)->DeleteLocalRef(jenv, jstr);
11301449Stomee 			return (NULL);
11311449Stomee 		}
11321449Stomee 		argv[i] = malloc(strlen(str) + 1);
11331449Stomee 		if (!argv[i]) {
11341449Stomee 			dtj_throw_out_of_memory(jenv, "Failed to allocate arg");
11351449Stomee 			dtj_free_argv(argv);
11361449Stomee 			dtj_ReleaseStringNativeChars(jenv, jstr, str);
11371449Stomee 			(*jenv)->DeleteLocalRef(jenv, jstr);
11381449Stomee 			return (NULL);
11391449Stomee 		}
11401449Stomee 		(void) strcpy(argv[i], str);
11411449Stomee 		dtj_ReleaseStringNativeChars(jenv, jstr, str);
11421449Stomee 		(*jenv)->DeleteLocalRef(jenv, jstr);
11431449Stomee 		jstr = NULL;
11441449Stomee 	}
11451449Stomee 
11461449Stomee 	return (argv);
11471449Stomee }
11481449Stomee 
11491449Stomee char **
dtj_make_argv(JNIEnv * jenv,jstring command,int * argc)11501449Stomee dtj_make_argv(JNIEnv *jenv, jstring command, int *argc)
11511449Stomee {
11521449Stomee 	const char *ws = "\f\n\r\t\v ";
11531449Stomee 	char **argv = NULL; /* return value */
11541449Stomee 	const char *cmd; /* native command string */
11551449Stomee 	char *s; /* writable command */
11561449Stomee 	char *tok; /* token */
11571449Stomee 	int len;
11581449Stomee 
11591449Stomee 	if (!g_dtj_load_common) {
11601449Stomee 		dtj_throw_illegal_state(jenv,
11611449Stomee 		    "dtj_load_common() has not been called");
11621449Stomee 		return (NULL);
11631449Stomee 	}
11641449Stomee 
11651449Stomee 	if (!command) {
11661449Stomee 		dtj_throw_null_pointer(jenv, "command is null");
11671449Stomee 		return (NULL);
11681449Stomee 	} else if ((*jenv)->GetStringLength(jenv, command) == 0) {
11691449Stomee 		dtj_throw_illegal_argument(jenv, "command is empty");
11701449Stomee 		return (NULL);
11711449Stomee 	}
11721449Stomee 
11731449Stomee 	cmd = dtj_GetStringNativeChars(jenv, command);
11741449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
11751449Stomee 		return (NULL);
11761449Stomee 	}
11771449Stomee 	len = strlen(cmd);
11781449Stomee 	s = malloc(len + 1);
11791449Stomee 	if (!s) {
11801449Stomee 		dtj_throw_out_of_memory(jenv,
11811449Stomee 		    "failed to allocate command string");
11821449Stomee 		dtj_ReleaseStringNativeChars(jenv, command, cmd);
11831449Stomee 		return (NULL);
11841449Stomee 	}
11851449Stomee 	(void) strcpy(s, cmd);
11861449Stomee 	/*
11871449Stomee 	 * Initialize all string pointers to NULL so that in case of an error
11881449Stomee 	 * filling in the array, free_argv() will not attempt to free the
11891449Stomee 	 * unallocated elements.  Also NULL-terminate the string array for
11901449Stomee 	 * functions that expect terminating NULL rather than rely on argc.
11911449Stomee 	 * Allow for maximum length resulting from single-character tokens
11921449Stomee 	 * separated by single spaces.
11931449Stomee 	 */
11941449Stomee 	argv = uu_zalloc(sizeof (char *) * (len / 2 + 1));
11951449Stomee 	if (!argv) {
11961449Stomee 		dtj_throw_out_of_memory(jenv, "failed to allocate args array");
11971449Stomee 		free(s);
11981449Stomee 		dtj_ReleaseStringNativeChars(jenv, command, cmd);
11991449Stomee 		return (NULL);
12001449Stomee 	}
12011449Stomee 
12021449Stomee 	*argc = 0;
12031449Stomee 	for (tok = strtok(s, ws); tok != NULL; tok = strtok(NULL, ws)) {
12041449Stomee 		argv[*argc] = malloc(strlen(tok) + 1);
12051449Stomee 		if (!argv[*argc]) {
12061449Stomee 			dtj_throw_out_of_memory(jenv, "Failed to allocate arg");
12071449Stomee 			dtj_free_argv(argv);
12081449Stomee 			free(s);
12091449Stomee 			dtj_ReleaseStringNativeChars(jenv, command, cmd);
12101449Stomee 			return (NULL);
12111449Stomee 		}
12121449Stomee 		(void) strcpy(argv[(*argc)++], tok);
12131449Stomee 	}
12141449Stomee 
12151449Stomee 	if (*argc == 0) {
12161449Stomee 		dtj_throw_illegal_argument(jenv, "command is blank");
12171449Stomee 		dtj_free_argv(argv);
12181449Stomee 		free(s);
12191449Stomee 		dtj_ReleaseStringNativeChars(jenv, command, cmd);
12201449Stomee 		return (NULL);
12211449Stomee 	}
12221449Stomee 
12231449Stomee 	free(s);
12241449Stomee 	dtj_ReleaseStringNativeChars(jenv, command, cmd);
12251449Stomee 	return (argv);
12261449Stomee }
12271449Stomee 
12281449Stomee void
dtj_free_argv(char ** argv)12291449Stomee dtj_free_argv(char **argv)
12301449Stomee {
12311449Stomee 	if (argv) {
12321449Stomee 		char **s = argv;
12331449Stomee 		while (*s) {
12341449Stomee 			free((void *)*s);
12351449Stomee 			*s++ = NULL;
12361449Stomee 		}
12371449Stomee 		free((void *)argv);
12381449Stomee 	}
12391449Stomee }
12401449Stomee 
12411449Stomee 
12421449Stomee /* Wrappers for uu_list_t */
12431449Stomee 
12441449Stomee int
12451449Stomee /* ARGSUSED */
dtj_pointer_list_entry_cmp(const void * v1,const void * v2,void * arg)12461449Stomee dtj_pointer_list_entry_cmp(const void *v1, const void *v2, void *arg)
12471449Stomee {
12481449Stomee 	const dtj_pointer_list_entry_t *p1 = v1;
12491449Stomee 	const dtj_pointer_list_entry_t *p2 = v2;
12501449Stomee 
12511449Stomee 	/*
12521449Stomee 	 * It is not valid to compare pointers using the relational operators
12531449Stomee 	 * unless they point to elements in the same array.
12541449Stomee 	 */
12551717Swesolows 	uint64_t x = (uintptr_t)p1->dple_ptr;
12561717Swesolows 	uint64_t y = (uintptr_t)p2->dple_ptr;
12571449Stomee 	int rc;
12581449Stomee 	rc = ((x > y) ? 1 : ((x < y) ? -1 : 0));
12591449Stomee 	return (rc);
12601449Stomee }
12611449Stomee 
12621449Stomee int
12631449Stomee /* ARGSUSED */
dtj_string_list_entry_cmp(const void * v1,const void * v2,void * arg)12641449Stomee dtj_string_list_entry_cmp(const void *v1, const void *v2, void *arg)
12651449Stomee {
12661449Stomee 	const dtj_string_list_entry_t *p1 = v1;
12671449Stomee 	const dtj_string_list_entry_t *p2 = v2;
12681449Stomee 	const char *s1 = p1->dsle_value;
12691449Stomee 	const char *s2 = p2->dsle_value;
12701449Stomee 	if (s1 == NULL) {
12711449Stomee 		return (s2 == NULL ? 0 : -1);
12721449Stomee 	}
12731449Stomee 	if (s2 == NULL) {
12741449Stomee 		return (1);
12751449Stomee 	}
12761449Stomee 	return (strcmp(s1, s2));
12771449Stomee }
12781449Stomee 
12791449Stomee static boolean_t
dtj_check_pointer_pool(void)12801449Stomee dtj_check_pointer_pool(void)
12811449Stomee {
12821449Stomee 	if (g_pointer_pool == NULL) {
12831449Stomee 		g_pointer_pool = uu_list_pool_create("g_pointer_pool",
12841449Stomee 		    sizeof (dtj_pointer_list_entry_t),
12851449Stomee 		    offsetof(dtj_pointer_list_entry_t, dple_node),
12861449Stomee 		    dtj_pointer_list_entry_cmp,
12871449Stomee 		    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
12881449Stomee 		if (g_pointer_pool == NULL) {
12891449Stomee 			return (B_FALSE);
12901449Stomee 		}
12911449Stomee 	}
12921449Stomee 	return (B_TRUE);
12931449Stomee }
12941449Stomee 
12951449Stomee uu_list_t *
dtj_pointer_list_create(void)12961449Stomee dtj_pointer_list_create(void)
12971449Stomee {
12981449Stomee 	uu_list_t *list;
12991449Stomee 
13001449Stomee 	if (!dtj_check_pointer_pool()) {
13011449Stomee 		return (NULL);
13021449Stomee 	}
13031449Stomee 
13041449Stomee 	list = uu_list_create(g_pointer_pool, NULL,
13051449Stomee 	    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
13061449Stomee 	return (list);
13071449Stomee }
13081449Stomee 
13091449Stomee dtj_pointer_list_entry_t *
dtj_pointer_list_entry_create(void * p)13101449Stomee dtj_pointer_list_entry_create(void *p)
13111449Stomee {
13121449Stomee 	dtj_pointer_list_entry_t *e;
13131449Stomee 
13141449Stomee 	if (!dtj_check_pointer_pool()) {
13151449Stomee 		return (NULL);
13161449Stomee 	}
13171449Stomee 
13181449Stomee 	e = uu_zalloc(sizeof (dtj_pointer_list_entry_t));
13191449Stomee 	if (e) {
13201449Stomee 		uu_list_node_init(e, &e->dple_node, g_pointer_pool);
13211449Stomee 		e->dple_ptr = p;
13221449Stomee 	}
13231449Stomee 	return (e);
13241449Stomee }
13251449Stomee 
13261449Stomee static boolean_t
dtj_check_string_pool(void)13271449Stomee dtj_check_string_pool(void)
13281449Stomee {
13291449Stomee 	if (g_string_pool == NULL) {
13301449Stomee 		g_string_pool = uu_list_pool_create("g_string_pool",
13311449Stomee 		    sizeof (dtj_string_list_entry_t),
13321449Stomee 		    offsetof(dtj_string_list_entry_t, dsle_node),
13331449Stomee 		    dtj_string_list_entry_cmp,
13341449Stomee 		    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
13351449Stomee 		if (g_string_pool == NULL) {
13361449Stomee 			return (B_FALSE);
13371449Stomee 		}
13381449Stomee 	}
13391449Stomee 	return (B_TRUE);
13401449Stomee }
13411449Stomee 
13421449Stomee uu_list_t *
dtj_string_list_create(void)13431449Stomee dtj_string_list_create(void)
13441449Stomee {
13451449Stomee 	uu_list_t *list;
13461449Stomee 
13471449Stomee 	if (!dtj_check_string_pool()) {
13481449Stomee 		return (NULL);
13491449Stomee 	}
13501449Stomee 
13511449Stomee 	list = uu_list_create(g_string_pool, NULL,
13521449Stomee 	    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
13531449Stomee 	return (list);
13541449Stomee }
13551449Stomee 
13561449Stomee dtj_string_list_entry_t *
dtj_string_list_entry_create(const char * s)13571449Stomee dtj_string_list_entry_create(const char *s)
13581449Stomee {
13591449Stomee 	dtj_string_list_entry_t *e;
13601449Stomee 
13611449Stomee 	if (!dtj_check_string_pool()) {
13621449Stomee 		return (NULL);
13631449Stomee 	}
13641449Stomee 
13651449Stomee 	e = uu_zalloc(sizeof (dtj_string_list_entry_t));
13661449Stomee 	if (e) {
13671449Stomee 		uu_list_node_init(e, &e->dsle_node, g_string_pool);
13681449Stomee 		if (s) {
13691449Stomee 			e->dsle_value = malloc(strlen(s) + 1);
13701449Stomee 			if (e->dsle_value) {
13711449Stomee 				(void) strcpy(e->dsle_value, s);
13721449Stomee 			} else {
13731449Stomee 				uu_list_node_fini(e, &e->dsle_node,
13741449Stomee 				    g_string_pool);
13751449Stomee 				uu_free(e);
13761449Stomee 				e = NULL;
13771449Stomee 			}
13781449Stomee 		}
13791449Stomee 	}
13801449Stomee 	return (e);
13811449Stomee }
13821449Stomee 
13831449Stomee void
dtj_pointer_list_entry_destroy(void * v,dtj_value_destroy_f * value_destroy,void * arg)13841449Stomee dtj_pointer_list_entry_destroy(void *v,
13851449Stomee     dtj_value_destroy_f *value_destroy, void *arg)
13861449Stomee {
13871449Stomee 	if (v) {
13881449Stomee 		dtj_pointer_list_entry_t *e = v;
13891449Stomee 		if (value_destroy) {
13901449Stomee 			value_destroy(e->dple_ptr, arg);
13911449Stomee 		}
13921449Stomee 		uu_list_node_fini(e, &e->dple_node, g_pointer_pool);
13931449Stomee 		e->dple_ptr = NULL;
13941449Stomee 		uu_free(v);
13951449Stomee 	}
13961449Stomee }
13971449Stomee 
13981449Stomee void
13991449Stomee /* ARGSUSED */
dtj_string_list_entry_destroy(void * v,void * arg)14001449Stomee dtj_string_list_entry_destroy(void *v, void *arg)
14011449Stomee {
14021449Stomee 	if (v) {
14031449Stomee 		dtj_string_list_entry_t *e = v;
14041449Stomee 		free(e->dsle_value);
14051449Stomee 		uu_list_node_fini(e, &e->dsle_node, g_string_pool);
14061449Stomee 		e->dsle_value = NULL;
14071449Stomee 		uu_free(v);
14081449Stomee 	}
14091449Stomee }
14101449Stomee 
14111449Stomee void
dtj_list_clear(uu_list_t * list,dtj_value_destroy_f * value_destroy,void * arg)14121449Stomee dtj_list_clear(uu_list_t *list, dtj_value_destroy_f *value_destroy,
14131449Stomee     void *arg)
14141449Stomee {
14151449Stomee 	void *cookie; /* needed for uu_list_teardown */
14161449Stomee 	void *value;
14171449Stomee 
14181449Stomee 	if (!list) {
14191449Stomee 		return;
14201449Stomee 	}
14211449Stomee 
14221449Stomee 	cookie = NULL;
14231449Stomee 	if (value_destroy) {
14241449Stomee 		while ((value = uu_list_teardown(list, &cookie)) != NULL) {
14251449Stomee 			value_destroy(value, arg);
14261449Stomee 		}
14271449Stomee 	} else {
14281449Stomee 		while ((value = uu_list_teardown(list, &cookie)) != NULL) {
14291449Stomee 		}
14301449Stomee 	}
14311449Stomee }
14321449Stomee 
14331449Stomee void
dtj_list_destroy(uu_list_t * list,dtj_value_destroy_f * value_destroy,void * arg)14341449Stomee dtj_list_destroy(uu_list_t *list,
14351449Stomee     dtj_value_destroy_f *value_destroy, void *arg)
14361449Stomee {
14371449Stomee 	dtj_list_clear(list, value_destroy, arg);
14381449Stomee 	uu_list_destroy(list);
14391449Stomee }
14401449Stomee 
14411449Stomee void
dtj_pointer_list_clear(uu_list_t * list,dtj_value_destroy_f * value_destroy,void * arg)14421449Stomee dtj_pointer_list_clear(uu_list_t *list,
14431449Stomee     dtj_value_destroy_f *value_destroy, void *arg)
14441449Stomee {
14451449Stomee 	void *cookie; /* needed for uu_list_teardown */
14461449Stomee 	dtj_pointer_list_entry_t *e;
14471449Stomee 
14481449Stomee 	if (!list) {
14491449Stomee 		return;
14501449Stomee 	}
14511449Stomee 
14521449Stomee 	cookie = NULL;
14531449Stomee 	while ((e = uu_list_teardown(list, &cookie)) != NULL) {
14541449Stomee 		dtj_pointer_list_entry_destroy(e, value_destroy, arg);
14551449Stomee 	}
14561449Stomee }
14571449Stomee 
14581449Stomee void
dtj_pointer_list_destroy(uu_list_t * list,dtj_value_destroy_f * value_destroy,void * arg)14591449Stomee dtj_pointer_list_destroy(uu_list_t *list,
14601449Stomee     dtj_value_destroy_f *value_destroy, void *arg)
14611449Stomee {
14621449Stomee 	dtj_pointer_list_clear(list, value_destroy, arg);
14631449Stomee 	uu_list_destroy(list);
14641449Stomee }
14651449Stomee 
14661449Stomee void
dtj_string_list_clear(uu_list_t * list)14671449Stomee dtj_string_list_clear(uu_list_t *list)
14681449Stomee {
14691449Stomee 	dtj_list_clear(list, dtj_string_list_entry_destroy, NULL);
14701449Stomee }
14711449Stomee 
14721449Stomee void
dtj_string_list_destroy(uu_list_t * list)14731449Stomee dtj_string_list_destroy(uu_list_t *list)
14741449Stomee {
14751449Stomee 	dtj_list_destroy(list, dtj_string_list_entry_destroy, NULL);
14761449Stomee }
14771449Stomee 
14781449Stomee boolean_t
dtj_list_empty(uu_list_t * list)14791449Stomee dtj_list_empty(uu_list_t *list)
14801449Stomee {
14811449Stomee 	return (uu_list_numnodes(list) == 0);
14821449Stomee }
14831449Stomee 
14841449Stomee boolean_t
dtj_list_add(uu_list_t * list,void * value)14851449Stomee dtj_list_add(uu_list_t *list, void *value)
14861449Stomee {
14871449Stomee 	return (uu_list_insert_before(list, NULL, value) == 0);
14881449Stomee }
14891449Stomee 
14901449Stomee boolean_t
dtj_pointer_list_add(uu_list_t * list,void * p)14911449Stomee dtj_pointer_list_add(uu_list_t *list, void *p)
14921449Stomee {
14931449Stomee 	dtj_pointer_list_entry_t *e = dtj_pointer_list_entry_create(p);
14941449Stomee 	if (!e) {
14951449Stomee 		return (B_FALSE);
14961449Stomee 	}
14971449Stomee 	return (dtj_list_add(list, e));
14981449Stomee }
14991449Stomee 
15001449Stomee void *
dtj_pointer_list_walk_next(uu_list_walk_t * itr)15011449Stomee dtj_pointer_list_walk_next(uu_list_walk_t *itr)
15021449Stomee {
15031449Stomee 	dtj_pointer_list_entry_t *e = uu_list_walk_next(itr);
15041449Stomee 	if (!e) {
15051449Stomee 		return (DTJ_INVALID_PTR);
15061449Stomee 	}
15071449Stomee 	return (e->dple_ptr);
15081449Stomee }
15091449Stomee 
15101449Stomee void *
dtj_pointer_list_first(uu_list_t * list)15111449Stomee dtj_pointer_list_first(uu_list_t *list)
15121449Stomee {
15131449Stomee 	dtj_pointer_list_entry_t *e = uu_list_first(list);
15141449Stomee 	if (!e) {
15151449Stomee 		/* NULL is a valid value; use -1 for invalid */
15161449Stomee 		return (DTJ_INVALID_PTR);
15171449Stomee 	}
15181449Stomee 	return (e->dple_ptr);
15191449Stomee }
15201449Stomee 
15211449Stomee void *
dtj_pointer_list_last(uu_list_t * list)15221449Stomee dtj_pointer_list_last(uu_list_t *list)
15231449Stomee {
15241449Stomee 	dtj_pointer_list_entry_t *e = uu_list_last(list);
15251449Stomee 	if (!e) {
15261449Stomee 		/* NULL is a valid value; use -1 for invalid */
15271449Stomee 		return (DTJ_INVALID_PTR);
15281449Stomee 	}
15291449Stomee 	return (e->dple_ptr);
15301449Stomee }
15311449Stomee 
15321449Stomee boolean_t
dtj_string_list_add(uu_list_t * list,const char * s)15331449Stomee dtj_string_list_add(uu_list_t *list, const char *s)
15341449Stomee {
15351449Stomee 	dtj_string_list_entry_t *e = dtj_string_list_entry_create(s);
15361449Stomee 	if (!e) {
15371449Stomee 		return (B_FALSE);
15381449Stomee 	}
15391449Stomee 	return (dtj_list_add(list, e));
15401449Stomee }
15411449Stomee 
15421449Stomee const char *
dtj_string_list_walk_next(uu_list_walk_t * itr)15431449Stomee dtj_string_list_walk_next(uu_list_walk_t *itr)
15441449Stomee {
15451449Stomee 	dtj_string_list_entry_t *e = uu_list_walk_next(itr);
15461449Stomee 	if (!e) {
15471449Stomee 		return (DTJ_INVALID_STR);
15481449Stomee 	}
15491449Stomee 	return (e->dsle_value);
15501449Stomee }
15511449Stomee 
15521449Stomee const char *
dtj_string_list_first(uu_list_t * list)15531449Stomee dtj_string_list_first(uu_list_t *list)
15541449Stomee {
15551449Stomee 	dtj_string_list_entry_t *e = uu_list_first(list);
15561449Stomee 	if (!e) {
15571449Stomee 		/* NULL is a valid string value; use -1 for invalid */
15581449Stomee 		return (DTJ_INVALID_STR);
15591449Stomee 	}
15601449Stomee 	return (e->dsle_value);
15611449Stomee }
15621449Stomee 
15631449Stomee const char *
dtj_string_list_last(uu_list_t * list)15641449Stomee dtj_string_list_last(uu_list_t *list)
15651449Stomee {
15661449Stomee 	dtj_string_list_entry_t *e = uu_list_last(list);
15671449Stomee 	if (!e) {
15681449Stomee 		/* NULL is a valid string value; use -1 for invalid */
15691449Stomee 		return (DTJ_INVALID_STR);
15701449Stomee 	}
15711449Stomee 	return (e->dsle_value);
15721449Stomee }
1573