| 1 | // jni.cc - JNI implementation, including the jump table.
|
|---|
| 2 |
|
|---|
| 3 | /* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation
|
|---|
| 4 |
|
|---|
| 5 | This file is part of libgcj.
|
|---|
| 6 |
|
|---|
| 7 | This software is copyrighted work licensed under the terms of the
|
|---|
| 8 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
|---|
| 9 | details. */
|
|---|
| 10 |
|
|---|
| 11 | #include <config.h>
|
|---|
| 12 |
|
|---|
| 13 | #include <stddef.h>
|
|---|
| 14 | #include <string.h>
|
|---|
| 15 |
|
|---|
| 16 | #include <gcj/cni.h>
|
|---|
| 17 | #include <jvm.h>
|
|---|
| 18 | #include <java-assert.h>
|
|---|
| 19 | #include <jni.h>
|
|---|
| 20 | #ifdef ENABLE_JVMPI
|
|---|
| 21 | #include <jvmpi.h>
|
|---|
| 22 | #endif
|
|---|
| 23 |
|
|---|
| 24 | #include <java/lang/Class.h>
|
|---|
| 25 | #include <java/lang/ClassLoader.h>
|
|---|
| 26 | #include <java/lang/Throwable.h>
|
|---|
| 27 | #include <java/lang/ArrayIndexOutOfBoundsException.h>
|
|---|
| 28 | #include <java/lang/StringIndexOutOfBoundsException.h>
|
|---|
| 29 | #include <java/lang/UnsatisfiedLinkError.h>
|
|---|
| 30 | #include <java/lang/InstantiationException.h>
|
|---|
| 31 | #include <java/lang/NoSuchFieldError.h>
|
|---|
| 32 | #include <java/lang/NoSuchMethodError.h>
|
|---|
| 33 | #include <java/lang/reflect/Constructor.h>
|
|---|
| 34 | #include <java/lang/reflect/Method.h>
|
|---|
| 35 | #include <java/lang/reflect/Modifier.h>
|
|---|
| 36 | #include <java/lang/OutOfMemoryError.h>
|
|---|
| 37 | #include <java/util/IdentityHashMap.h>
|
|---|
| 38 | #include <java/lang/Integer.h>
|
|---|
| 39 | #include <java/lang/ThreadGroup.h>
|
|---|
| 40 | #include <java/lang/Thread.h>
|
|---|
| 41 |
|
|---|
| 42 | #include <gcj/method.h>
|
|---|
| 43 | #include <gcj/field.h>
|
|---|
| 44 |
|
|---|
| 45 | #include <java-interp.h>
|
|---|
| 46 | #include <java-threads.h>
|
|---|
| 47 |
|
|---|
| 48 | using namespace gcj;
|
|---|
| 49 |
|
|---|
| 50 | // This enum is used to select different template instantiations in
|
|---|
| 51 | // the invocation code.
|
|---|
| 52 | enum invocation_type
|
|---|
| 53 | {
|
|---|
| 54 | normal,
|
|---|
| 55 | nonvirtual,
|
|---|
| 56 | static_type,
|
|---|
| 57 | constructor
|
|---|
| 58 | };
|
|---|
| 59 |
|
|---|
| 60 | // Forward declarations.
|
|---|
| 61 | extern struct JNINativeInterface _Jv_JNIFunctions;
|
|---|
| 62 | extern struct JNIInvokeInterface _Jv_JNI_InvokeFunctions;
|
|---|
| 63 |
|
|---|
| 64 | // Number of slots in the default frame. The VM must allow at least
|
|---|
| 65 | // 16.
|
|---|
| 66 | #define FRAME_SIZE 32
|
|---|
| 67 |
|
|---|
| 68 | // Mark value indicating this is an overflow frame.
|
|---|
| 69 | #define MARK_NONE 0
|
|---|
| 70 | // Mark value indicating this is a user frame.
|
|---|
| 71 | #define MARK_USER 1
|
|---|
| 72 | // Mark value indicating this is a system frame.
|
|---|
| 73 | #define MARK_SYSTEM 2
|
|---|
| 74 |
|
|---|
| 75 | // This structure is used to keep track of local references.
|
|---|
| 76 | struct _Jv_JNI_LocalFrame
|
|---|
| 77 | {
|
|---|
| 78 | // This is true if this frame object represents a pushed frame (eg
|
|---|
| 79 | // from PushLocalFrame).
|
|---|
| 80 | int marker : 2;
|
|---|
| 81 |
|
|---|
| 82 | // Number of elements in frame.
|
|---|
| 83 | int size : 30;
|
|---|
| 84 |
|
|---|
| 85 | // Next frame in chain.
|
|---|
| 86 | _Jv_JNI_LocalFrame *next;
|
|---|
| 87 |
|
|---|
| 88 | // The elements. These are allocated using the C "struct hack".
|
|---|
| 89 | jobject vec[0];
|
|---|
| 90 | };
|
|---|
| 91 |
|
|---|
| 92 | // This holds a reference count for all local references.
|
|---|
| 93 | static java::util::IdentityHashMap *local_ref_table;
|
|---|
| 94 | // This holds a reference count for all global references.
|
|---|
| 95 | static java::util::IdentityHashMap *global_ref_table;
|
|---|
| 96 |
|
|---|
| 97 | // The only VM.
|
|---|
| 98 | static JavaVM *the_vm;
|
|---|
| 99 |
|
|---|
| 100 | #ifdef ENABLE_JVMPI
|
|---|
| 101 | // The only JVMPI interface description.
|
|---|
| 102 | static JVMPI_Interface _Jv_JVMPI_Interface;
|
|---|
| 103 |
|
|---|
| 104 | static jint
|
|---|
| 105 | jvmpiEnableEvent (jint event_type, void *)
|
|---|
| 106 | {
|
|---|
| 107 | switch (event_type)
|
|---|
| 108 | {
|
|---|
| 109 | case JVMPI_EVENT_OBJECT_ALLOC:
|
|---|
| 110 | _Jv_JVMPI_Notify_OBJECT_ALLOC = _Jv_JVMPI_Interface.NotifyEvent;
|
|---|
| 111 | break;
|
|---|
| 112 |
|
|---|
| 113 | case JVMPI_EVENT_THREAD_START:
|
|---|
| 114 | _Jv_JVMPI_Notify_THREAD_START = _Jv_JVMPI_Interface.NotifyEvent;
|
|---|
| 115 | break;
|
|---|
| 116 |
|
|---|
| 117 | case JVMPI_EVENT_THREAD_END:
|
|---|
| 118 | _Jv_JVMPI_Notify_THREAD_END = _Jv_JVMPI_Interface.NotifyEvent;
|
|---|
| 119 | break;
|
|---|
| 120 |
|
|---|
| 121 | default:
|
|---|
| 122 | return JVMPI_NOT_AVAILABLE;
|
|---|
| 123 | }
|
|---|
| 124 |
|
|---|
| 125 | return JVMPI_SUCCESS;
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | static jint
|
|---|
| 129 | jvmpiDisableEvent (jint event_type, void *)
|
|---|
| 130 | {
|
|---|
| 131 | switch (event_type)
|
|---|
| 132 | {
|
|---|
| 133 | case JVMPI_EVENT_OBJECT_ALLOC:
|
|---|
| 134 | _Jv_JVMPI_Notify_OBJECT_ALLOC = NULL;
|
|---|
| 135 | break;
|
|---|
| 136 |
|
|---|
| 137 | default:
|
|---|
| 138 | return JVMPI_NOT_AVAILABLE;
|
|---|
| 139 | }
|
|---|
| 140 |
|
|---|
| 141 | return JVMPI_SUCCESS;
|
|---|
| 142 | }
|
|---|
| 143 | #endif
|
|---|
| 144 |
|
|---|
| 145 | |
|---|
| 146 |
|
|---|
| 147 |
|
|---|
| 148 | void
|
|---|
| 149 | _Jv_JNI_Init (void)
|
|---|
| 150 | {
|
|---|
| 151 | local_ref_table = new java::util::IdentityHashMap;
|
|---|
| 152 | global_ref_table = new java::util::IdentityHashMap;
|
|---|
| 153 |
|
|---|
| 154 | #ifdef ENABLE_JVMPI
|
|---|
| 155 | _Jv_JVMPI_Interface.version = 1;
|
|---|
| 156 | _Jv_JVMPI_Interface.EnableEvent = &jvmpiEnableEvent;
|
|---|
| 157 | _Jv_JVMPI_Interface.DisableEvent = &jvmpiDisableEvent;
|
|---|
| 158 | _Jv_JVMPI_Interface.EnableGC = &_Jv_EnableGC;
|
|---|
| 159 | _Jv_JVMPI_Interface.DisableGC = &_Jv_DisableGC;
|
|---|
| 160 | _Jv_JVMPI_Interface.RunGC = &_Jv_RunGC;
|
|---|
| 161 | #endif
|
|---|
| 162 | }
|
|---|
| 163 |
|
|---|
| 164 | // Tell the GC that a certain pointer is live.
|
|---|
| 165 | static void
|
|---|
| 166 | mark_for_gc (jobject obj, java::util::IdentityHashMap *ref_table)
|
|---|
| 167 | {
|
|---|
| 168 | JvSynchronize sync (ref_table);
|
|---|
| 169 |
|
|---|
| 170 | using namespace java::lang;
|
|---|
| 171 | Integer *refcount = (Integer *) ref_table->get (obj);
|
|---|
| 172 | jint val = (refcount == NULL) ? 0 : refcount->intValue ();
|
|---|
| 173 | // FIXME: what about out of memory error?
|
|---|
| 174 | ref_table->put (obj, new Integer (val + 1));
|
|---|
| 175 | }
|
|---|
| 176 |
|
|---|
| 177 | // Unmark a pointer.
|
|---|
| 178 | static void
|
|---|
| 179 | unmark_for_gc (jobject obj, java::util::IdentityHashMap *ref_table)
|
|---|
| 180 | {
|
|---|
| 181 | JvSynchronize sync (ref_table);
|
|---|
| 182 |
|
|---|
| 183 | using namespace java::lang;
|
|---|
| 184 | Integer *refcount = (Integer *) ref_table->get (obj);
|
|---|
| 185 | JvAssert (refcount);
|
|---|
| 186 | jint val = refcount->intValue () - 1;
|
|---|
| 187 | JvAssert (val >= 0);
|
|---|
| 188 | if (val == 0)
|
|---|
| 189 | ref_table->remove (obj);
|
|---|
| 190 | else
|
|---|
| 191 | // FIXME: what about out of memory error?
|
|---|
| 192 | ref_table->put (obj, new Integer (val));
|
|---|
| 193 | }
|
|---|
| 194 |
|
|---|
| 195 | // "Unwrap" some random non-reference type. This exists to simplify
|
|---|
| 196 | // other template functions.
|
|---|
| 197 | template<typename T>
|
|---|
| 198 | static T
|
|---|
| 199 | unwrap (T val)
|
|---|
| 200 | {
|
|---|
| 201 | return val;
|
|---|
| 202 | }
|
|---|
| 203 |
|
|---|
| 204 | // Unwrap a weak reference, if required.
|
|---|
| 205 | template<typename T>
|
|---|
| 206 | static T *
|
|---|
| 207 | unwrap (T *obj)
|
|---|
| 208 | {
|
|---|
| 209 | using namespace gnu::gcj::runtime;
|
|---|
| 210 | // We can compare the class directly because JNIWeakRef is `final'.
|
|---|
| 211 | // Doing it this way is much faster.
|
|---|
| 212 | if (obj == NULL || obj->getClass () != &JNIWeakRef::class$)
|
|---|
| 213 | return obj;
|
|---|
| 214 | JNIWeakRef *wr = reinterpret_cast<JNIWeakRef *> (obj);
|
|---|
| 215 | return reinterpret_cast<T *> (wr->get ());
|
|---|
| 216 | }
|
|---|
| 217 |
|
|---|
| 218 | |
|---|
| 219 |
|
|---|
| 220 |
|
|---|
| 221 | static jobject
|
|---|
| 222 | _Jv_JNI_NewGlobalRef (JNIEnv *, jobject obj)
|
|---|
| 223 | {
|
|---|
| 224 | // This seems weird but I think it is correct.
|
|---|
| 225 | obj = unwrap (obj);
|
|---|
| 226 | mark_for_gc (obj, global_ref_table);
|
|---|
| 227 | return obj;
|
|---|
| 228 | }
|
|---|
| 229 |
|
|---|
| 230 | static void
|
|---|
| 231 | _Jv_JNI_DeleteGlobalRef (JNIEnv *, jobject obj)
|
|---|
| 232 | {
|
|---|
| 233 | // This seems weird but I think it is correct.
|
|---|
| 234 | obj = unwrap (obj);
|
|---|
| 235 | unmark_for_gc (obj, global_ref_table);
|
|---|
| 236 | }
|
|---|
| 237 |
|
|---|
| 238 | static void
|
|---|
| 239 | _Jv_JNI_DeleteLocalRef (JNIEnv *env, jobject obj)
|
|---|
| 240 | {
|
|---|
| 241 | _Jv_JNI_LocalFrame *frame;
|
|---|
| 242 |
|
|---|
| 243 | // This seems weird but I think it is correct.
|
|---|
| 244 | obj = unwrap (obj);
|
|---|
| 245 |
|
|---|
| 246 | for (frame = env->locals; frame != NULL; frame = frame->next)
|
|---|
| 247 | {
|
|---|
| 248 | for (int i = 0; i < frame->size; ++i)
|
|---|
| 249 | {
|
|---|
| 250 | if (frame->vec[i] == obj)
|
|---|
| 251 | {
|
|---|
| 252 | frame->vec[i] = NULL;
|
|---|
| 253 | unmark_for_gc (obj, local_ref_table);
|
|---|
| 254 | return;
|
|---|
| 255 | }
|
|---|
| 256 | }
|
|---|
| 257 |
|
|---|
| 258 | // Don't go past a marked frame.
|
|---|
| 259 | JvAssert (frame->marker == MARK_NONE);
|
|---|
| 260 | }
|
|---|
| 261 |
|
|---|
| 262 | JvAssert (0);
|
|---|
| 263 | }
|
|---|
| 264 |
|
|---|
| 265 | static jint
|
|---|
| 266 | _Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size)
|
|---|
| 267 | {
|
|---|
| 268 | // It is easier to just always allocate a new frame of the requested
|
|---|
| 269 | // size. This isn't the most efficient thing, but for now we don't
|
|---|
| 270 | // care. Note that _Jv_JNI_PushLocalFrame relies on this right now.
|
|---|
| 271 |
|
|---|
| 272 | _Jv_JNI_LocalFrame *frame;
|
|---|
| 273 | try
|
|---|
| 274 | {
|
|---|
| 275 | frame = (_Jv_JNI_LocalFrame *) _Jv_Malloc (sizeof (_Jv_JNI_LocalFrame)
|
|---|
| 276 | + size * sizeof (jobject));
|
|---|
| 277 | }
|
|---|
| 278 | catch (jthrowable t)
|
|---|
| 279 | {
|
|---|
| 280 | env->ex = t;
|
|---|
| 281 | return JNI_ERR;
|
|---|
| 282 | }
|
|---|
| 283 |
|
|---|
| 284 | frame->marker = MARK_NONE;
|
|---|
| 285 | frame->size = size;
|
|---|
| 286 | memset (&frame->vec[0], 0, size * sizeof (jobject));
|
|---|
| 287 | frame->next = env->locals;
|
|---|
| 288 | env->locals = frame;
|
|---|
| 289 |
|
|---|
| 290 | return 0;
|
|---|
| 291 | }
|
|---|
| 292 |
|
|---|
| 293 | static jint
|
|---|
| 294 | _Jv_JNI_PushLocalFrame (JNIEnv *env, jint size)
|
|---|
| 295 | {
|
|---|
| 296 | jint r = _Jv_JNI_EnsureLocalCapacity (env, size);
|
|---|
| 297 | if (r < 0)
|
|---|
| 298 | return r;
|
|---|
| 299 |
|
|---|
| 300 | // The new frame is on top.
|
|---|
| 301 | env->locals->marker = MARK_USER;
|
|---|
| 302 |
|
|---|
| 303 | return 0;
|
|---|
| 304 | }
|
|---|
| 305 |
|
|---|
| 306 | static jobject
|
|---|
| 307 | _Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj)
|
|---|
| 308 | {
|
|---|
| 309 | // This seems weird but I think it is correct.
|
|---|
| 310 | obj = unwrap (obj);
|
|---|
| 311 |
|
|---|
| 312 | // Try to find an open slot somewhere in the topmost frame.
|
|---|
| 313 | _Jv_JNI_LocalFrame *frame = env->locals;
|
|---|
| 314 | bool done = false, set = false;
|
|---|
| 315 | for (; frame != NULL && ! done; frame = frame->next)
|
|---|
| 316 | {
|
|---|
| 317 | for (int i = 0; i < frame->size; ++i)
|
|---|
| 318 | {
|
|---|
| 319 | if (frame->vec[i] == NULL)
|
|---|
| 320 | {
|
|---|
| 321 | set = true;
|
|---|
| 322 | done = true;
|
|---|
| 323 | frame->vec[i] = obj;
|
|---|
| 324 | break;
|
|---|
| 325 | }
|
|---|
| 326 | }
|
|---|
| 327 |
|
|---|
| 328 | // If we found a slot, or if the frame we just searched is the
|
|---|
| 329 | // mark frame, then we are done.
|
|---|
| 330 | if (done || frame == NULL || frame->marker != MARK_NONE)
|
|---|
| 331 | break;
|
|---|
| 332 | }
|
|---|
| 333 |
|
|---|
| 334 | if (! set)
|
|---|
| 335 | {
|
|---|
| 336 | // No slots, so we allocate a new frame. According to the spec
|
|---|
| 337 | // we could just die here. FIXME: return value.
|
|---|
| 338 | _Jv_JNI_EnsureLocalCapacity (env, 16);
|
|---|
| 339 | // We know the first element of the new frame will be ok.
|
|---|
| 340 | env->locals->vec[0] = obj;
|
|---|
| 341 | }
|
|---|
| 342 |
|
|---|
| 343 | mark_for_gc (obj, local_ref_table);
|
|---|
| 344 | return obj;
|
|---|
| 345 | }
|
|---|
| 346 |
|
|---|
| 347 | static jobject
|
|---|
| 348 | _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop)
|
|---|
| 349 | {
|
|---|
| 350 | _Jv_JNI_LocalFrame *rf = env->locals;
|
|---|
| 351 |
|
|---|
| 352 | bool done = false;
|
|---|
| 353 | while (rf != NULL && ! done)
|
|---|
| 354 | {
|
|---|
| 355 | for (int i = 0; i < rf->size; ++i)
|
|---|
| 356 | if (rf->vec[i] != NULL)
|
|---|
| 357 | unmark_for_gc (rf->vec[i], local_ref_table);
|
|---|
| 358 |
|
|---|
| 359 | // If the frame we just freed is the marker frame, we are done.
|
|---|
| 360 | done = (rf->marker == stop);
|
|---|
| 361 |
|
|---|
| 362 | _Jv_JNI_LocalFrame *n = rf->next;
|
|---|
| 363 | // When N==NULL, we've reached the stack-allocated frame, and we
|
|---|
| 364 | // must not free it. However, we must be sure to clear all its
|
|---|
| 365 | // elements, since we might conceivably reuse it.
|
|---|
| 366 | if (n == NULL)
|
|---|
| 367 | {
|
|---|
| 368 | memset (&rf->vec[0], 0, rf->size * sizeof (jobject));
|
|---|
| 369 | break;
|
|---|
| 370 | }
|
|---|
| 371 |
|
|---|
| 372 | _Jv_Free (rf);
|
|---|
| 373 | rf = n;
|
|---|
| 374 | }
|
|---|
| 375 |
|
|---|
| 376 | // Update the local frame information.
|
|---|
| 377 | env->locals = rf;
|
|---|
| 378 |
|
|---|
| 379 | return result == NULL ? NULL : _Jv_JNI_NewLocalRef (env, result);
|
|---|
| 380 | }
|
|---|
| 381 |
|
|---|
| 382 | static jobject
|
|---|
| 383 | _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result)
|
|---|
| 384 | {
|
|---|
| 385 | return _Jv_JNI_PopLocalFrame (env, result, MARK_USER);
|
|---|
| 386 | }
|
|---|
| 387 |
|
|---|
| 388 | // Pop a `system' frame from the stack. This is `extern "C"' as it is
|
|---|
| 389 | // used by the compiler.
|
|---|
| 390 | extern "C" void
|
|---|
| 391 | _Jv_JNI_PopSystemFrame (JNIEnv *env)
|
|---|
| 392 | {
|
|---|
| 393 | _Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM);
|
|---|
| 394 |
|
|---|
| 395 | if (env->ex)
|
|---|
| 396 | {
|
|---|
| 397 | jthrowable t = env->ex;
|
|---|
| 398 | env->ex = NULL;
|
|---|
| 399 | throw t;
|
|---|
| 400 | }
|
|---|
| 401 | }
|
|---|
| 402 |
|
|---|
| 403 | // This function is used from other template functions. It wraps the
|
|---|
| 404 | // return value appropriately; we specialize it so that object returns
|
|---|
| 405 | // are turned into local references.
|
|---|
| 406 | template<typename T>
|
|---|
| 407 | static T
|
|---|
| 408 | wrap_value (JNIEnv *, T value)
|
|---|
| 409 | {
|
|---|
| 410 | return value;
|
|---|
| 411 | }
|
|---|
| 412 |
|
|---|
| 413 | // This specialization is used for jobject, jclass, jstring, jarray,
|
|---|
| 414 | // etc.
|
|---|
| 415 | template<typename T>
|
|---|
| 416 | static T *
|
|---|
| 417 | wrap_value (JNIEnv *env, T *value)
|
|---|
| 418 | {
|
|---|
| 419 | return (value == NULL
|
|---|
| 420 | ? value
|
|---|
| 421 | : (T *) _Jv_JNI_NewLocalRef (env, (jobject) value));
|
|---|
| 422 | }
|
|---|
| 423 |
|
|---|
| 424 | |
|---|
| 425 |
|
|---|
| 426 |
|
|---|
| 427 | static jint
|
|---|
| 428 | _Jv_JNI_GetVersion (JNIEnv *)
|
|---|
| 429 | {
|
|---|
| 430 | return JNI_VERSION_1_2;
|
|---|
| 431 | }
|
|---|
| 432 |
|
|---|
| 433 | static jclass
|
|---|
| 434 | _Jv_JNI_DefineClass (JNIEnv *env, jobject loader,
|
|---|
| 435 | const jbyte *buf, jsize bufLen)
|
|---|
| 436 | {
|
|---|
| 437 | try
|
|---|
| 438 | {
|
|---|
| 439 | loader = unwrap (loader);
|
|---|
| 440 |
|
|---|
| 441 | jbyteArray bytes = JvNewByteArray (bufLen);
|
|---|
| 442 |
|
|---|
| 443 | jbyte *elts = elements (bytes);
|
|---|
| 444 | memcpy (elts, buf, bufLen * sizeof (jbyte));
|
|---|
| 445 |
|
|---|
| 446 | java::lang::ClassLoader *l
|
|---|
| 447 | = reinterpret_cast<java::lang::ClassLoader *> (loader);
|
|---|
| 448 |
|
|---|
| 449 | jclass result = l->defineClass (bytes, 0, bufLen);
|
|---|
| 450 | return (jclass) wrap_value (env, result);
|
|---|
| 451 | }
|
|---|
| 452 | catch (jthrowable t)
|
|---|
| 453 | {
|
|---|
| 454 | env->ex = t;
|
|---|
| 455 | return NULL;
|
|---|
| 456 | }
|
|---|
| 457 | }
|
|---|
| 458 |
|
|---|
| 459 | static jclass
|
|---|
| 460 | _Jv_JNI_FindClass (JNIEnv *env, const char *name)
|
|---|
| 461 | {
|
|---|
| 462 | // FIXME: assume that NAME isn't too long.
|
|---|
| 463 | int len = strlen (name);
|
|---|
| 464 | char s[len + 1];
|
|---|
| 465 | for (int i = 0; i <= len; ++i)
|
|---|
| 466 | s[i] = (name[i] == '/') ? '.' : name[i];
|
|---|
| 467 |
|
|---|
| 468 | jclass r = NULL;
|
|---|
| 469 | try
|
|---|
| 470 | {
|
|---|
| 471 | // This might throw an out of memory exception.
|
|---|
| 472 | jstring n = JvNewStringUTF (s);
|
|---|
| 473 |
|
|---|
| 474 | java::lang::ClassLoader *loader = NULL;
|
|---|
| 475 | if (env->klass != NULL)
|
|---|
| 476 | loader = env->klass->getClassLoader ();
|
|---|
| 477 |
|
|---|
| 478 | if (loader == NULL)
|
|---|
| 479 | {
|
|---|
| 480 | // FIXME: should use getBaseClassLoader, but we don't have that
|
|---|
| 481 | // yet.
|
|---|
| 482 | loader = java::lang::ClassLoader::getSystemClassLoader ();
|
|---|
| 483 | }
|
|---|
| 484 |
|
|---|
| 485 | r = loader->loadClass (n);
|
|---|
| 486 | }
|
|---|
| 487 | catch (jthrowable t)
|
|---|
| 488 | {
|
|---|
| 489 | env->ex = t;
|
|---|
| 490 | }
|
|---|
| 491 |
|
|---|
| 492 | return (jclass) wrap_value (env, r);
|
|---|
| 493 | }
|
|---|
| 494 |
|
|---|
| 495 | static jclass
|
|---|
| 496 | _Jv_JNI_GetSuperclass (JNIEnv *env, jclass clazz)
|
|---|
| 497 | {
|
|---|
| 498 | return (jclass) wrap_value (env, unwrap (clazz)->getSuperclass ());
|
|---|
| 499 | }
|
|---|
| 500 |
|
|---|
| 501 | static jboolean
|
|---|
| 502 | _Jv_JNI_IsAssignableFrom(JNIEnv *, jclass clazz1, jclass clazz2)
|
|---|
| 503 | {
|
|---|
| 504 | return unwrap (clazz1)->isAssignableFrom (unwrap (clazz2));
|
|---|
| 505 | }
|
|---|
| 506 |
|
|---|
| 507 | static jint
|
|---|
| 508 | _Jv_JNI_Throw (JNIEnv *env, jthrowable obj)
|
|---|
| 509 | {
|
|---|
| 510 | // We check in case the user did some funky cast.
|
|---|
| 511 | obj = unwrap (obj);
|
|---|
| 512 | JvAssert (obj != NULL && java::lang::Throwable::class$.isInstance (obj));
|
|---|
| 513 | env->ex = obj;
|
|---|
| 514 | return 0;
|
|---|
| 515 | }
|
|---|
| 516 |
|
|---|
| 517 | static jint
|
|---|
| 518 | _Jv_JNI_ThrowNew (JNIEnv *env, jclass clazz, const char *message)
|
|---|
| 519 | {
|
|---|
| 520 | using namespace java::lang::reflect;
|
|---|
| 521 |
|
|---|
| 522 | clazz = unwrap (clazz);
|
|---|
| 523 | JvAssert (java::lang::Throwable::class$.isAssignableFrom (clazz));
|
|---|
| 524 |
|
|---|
| 525 | int r = JNI_OK;
|
|---|
| 526 | try
|
|---|
| 527 | {
|
|---|
| 528 | JArray<jclass> *argtypes
|
|---|
| 529 | = (JArray<jclass> *) JvNewObjectArray (1, &java::lang::Class::class$,
|
|---|
| 530 | NULL);
|
|---|
| 531 |
|
|---|
| 532 | jclass *elts = elements (argtypes);
|
|---|
| 533 | elts[0] = &StringClass;
|
|---|
| 534 |
|
|---|
| 535 | Constructor *cons = clazz->getConstructor (argtypes);
|
|---|
| 536 |
|
|---|
| 537 | jobjectArray values = JvNewObjectArray (1, &StringClass, NULL);
|
|---|
| 538 | jobject *velts = elements (values);
|
|---|
| 539 | velts[0] = JvNewStringUTF (message);
|
|---|
| 540 |
|
|---|
| 541 | jobject obj = cons->newInstance (values);
|
|---|
| 542 |
|
|---|
| 543 | env->ex = reinterpret_cast<jthrowable> (obj);
|
|---|
| 544 | }
|
|---|
| 545 | catch (jthrowable t)
|
|---|
| 546 | {
|
|---|
| 547 | env->ex = t;
|
|---|
| 548 | r = JNI_ERR;
|
|---|
| 549 | }
|
|---|
| 550 |
|
|---|
| 551 | return r;
|
|---|
| 552 | }
|
|---|
| 553 |
|
|---|
| 554 | static jthrowable
|
|---|
| 555 | _Jv_JNI_ExceptionOccurred (JNIEnv *env)
|
|---|
| 556 | {
|
|---|
| 557 | return (jthrowable) wrap_value (env, env->ex);
|
|---|
| 558 | }
|
|---|
| 559 |
|
|---|
| 560 | static void
|
|---|
| 561 | _Jv_JNI_ExceptionDescribe (JNIEnv *env)
|
|---|
| 562 | {
|
|---|
| 563 | if (env->ex != NULL)
|
|---|
| 564 | env->ex->printStackTrace();
|
|---|
| 565 | }
|
|---|
| 566 |
|
|---|
| 567 | static void
|
|---|
| 568 | _Jv_JNI_ExceptionClear (JNIEnv *env)
|
|---|
| 569 | {
|
|---|
| 570 | env->ex = NULL;
|
|---|
| 571 | }
|
|---|
| 572 |
|
|---|
| 573 | static jboolean
|
|---|
| 574 | _Jv_JNI_ExceptionCheck (JNIEnv *env)
|
|---|
| 575 | {
|
|---|
| 576 | return env->ex != NULL;
|
|---|
| 577 | }
|
|---|
| 578 |
|
|---|
| 579 | static void
|
|---|
| 580 | _Jv_JNI_FatalError (JNIEnv *, const char *message)
|
|---|
| 581 | {
|
|---|
| 582 | JvFail (message);
|
|---|
| 583 | }
|
|---|
| 584 |
|
|---|
| 585 | |
|---|
| 586 |
|
|---|
| 587 |
|
|---|
| 588 | static jboolean
|
|---|
| 589 | _Jv_JNI_IsSameObject (JNIEnv *, jobject obj1, jobject obj2)
|
|---|
| 590 | {
|
|---|
| 591 | return unwrap (obj1) == unwrap (obj2);
|
|---|
| 592 | }
|
|---|
| 593 |
|
|---|
| 594 | static jobject
|
|---|
| 595 | _Jv_JNI_AllocObject (JNIEnv *env, jclass clazz)
|
|---|
| 596 | {
|
|---|
| 597 | jobject obj = NULL;
|
|---|
| 598 | using namespace java::lang::reflect;
|
|---|
| 599 |
|
|---|
| 600 | try
|
|---|
| 601 | {
|
|---|
| 602 | clazz = unwrap (clazz);
|
|---|
| 603 | JvAssert (clazz && ! clazz->isArray ());
|
|---|
| 604 | if (clazz->isInterface() || Modifier::isAbstract(clazz->getModifiers()))
|
|---|
| 605 | env->ex = new java::lang::InstantiationException ();
|
|---|
| 606 | else
|
|---|
| 607 | {
|
|---|
| 608 | // FIXME: will this work for String?
|
|---|
| 609 | obj = JvAllocObject (clazz);
|
|---|
| 610 | }
|
|---|
| 611 | }
|
|---|
| 612 | catch (jthrowable t)
|
|---|
| 613 | {
|
|---|
| 614 | env->ex = t;
|
|---|
| 615 | }
|
|---|
| 616 |
|
|---|
| 617 | return wrap_value (env, obj);
|
|---|
| 618 | }
|
|---|
| 619 |
|
|---|
| 620 | static jclass
|
|---|
| 621 | _Jv_JNI_GetObjectClass (JNIEnv *env, jobject obj)
|
|---|
| 622 | {
|
|---|
| 623 | obj = unwrap (obj);
|
|---|
| 624 | JvAssert (obj);
|
|---|
| 625 | return (jclass) wrap_value (env, obj->getClass());
|
|---|
| 626 | }
|
|---|
| 627 |
|
|---|
| 628 | static jboolean
|
|---|
| 629 | _Jv_JNI_IsInstanceOf (JNIEnv *, jobject obj, jclass clazz)
|
|---|
| 630 | {
|
|---|
| 631 | return unwrap (clazz)->isInstance(unwrap (obj));
|
|---|
| 632 | }
|
|---|
| 633 |
|
|---|
| 634 | |
|---|
| 635 |
|
|---|
| 636 |
|
|---|
| 637 | //
|
|---|
| 638 | // This section concerns method invocation.
|
|---|
| 639 | //
|
|---|
| 640 |
|
|---|
| 641 | template<jboolean is_static>
|
|---|
| 642 | static jmethodID
|
|---|
| 643 | _Jv_JNI_GetAnyMethodID (JNIEnv *env, jclass clazz,
|
|---|
| 644 | const char *name, const char *sig)
|
|---|
| 645 | {
|
|---|
| 646 | try
|
|---|
| 647 | {
|
|---|
| 648 | clazz = unwrap (clazz);
|
|---|
| 649 | _Jv_InitClass (clazz);
|
|---|
| 650 |
|
|---|
| 651 | _Jv_Utf8Const *name_u = _Jv_makeUtf8Const ((char *) name, -1);
|
|---|
| 652 |
|
|---|
| 653 | // FIXME: assume that SIG isn't too long.
|
|---|
| 654 | int len = strlen (sig);
|
|---|
| 655 | char s[len + 1];
|
|---|
| 656 | for (int i = 0; i <= len; ++i)
|
|---|
| 657 | s[i] = (sig[i] == '/') ? '.' : sig[i];
|
|---|
| 658 | _Jv_Utf8Const *sig_u = _Jv_makeUtf8Const ((char *) s, -1);
|
|---|
| 659 |
|
|---|
| 660 | JvAssert (! clazz->isPrimitive());
|
|---|
| 661 |
|
|---|
| 662 | using namespace java::lang::reflect;
|
|---|
| 663 |
|
|---|
| 664 | while (clazz != NULL)
|
|---|
| 665 | {
|
|---|
| 666 | jint count = JvNumMethods (clazz);
|
|---|
| 667 | jmethodID meth = JvGetFirstMethod (clazz);
|
|---|
| 668 |
|
|---|
| 669 | for (jint i = 0; i < count; ++i)
|
|---|
| 670 | {
|
|---|
| 671 | if (((is_static && Modifier::isStatic (meth->accflags))
|
|---|
| 672 | || (! is_static && ! Modifier::isStatic (meth->accflags)))
|
|---|
| 673 | && _Jv_equalUtf8Consts (meth->name, name_u)
|
|---|
| 674 | && _Jv_equalUtf8Consts (meth->signature, sig_u))
|
|---|
| 675 | return meth;
|
|---|
| 676 |
|
|---|
| 677 | meth = meth->getNextMethod();
|
|---|
| 678 | }
|
|---|
| 679 |
|
|---|
| 680 | clazz = clazz->getSuperclass ();
|
|---|
| 681 | }
|
|---|
| 682 |
|
|---|
| 683 | env->ex = new java::lang::NoSuchMethodError ();
|
|---|
| 684 | }
|
|---|
| 685 | catch (jthrowable t)
|
|---|
| 686 | {
|
|---|
| 687 | env->ex = t;
|
|---|
| 688 | }
|
|---|
| 689 |
|
|---|
| 690 | return NULL;
|
|---|
| 691 | }
|
|---|
| 692 |
|
|---|
| 693 | // This is a helper function which turns a va_list into an array of
|
|---|
| 694 | // `jvalue's. It needs signature information in order to do its work.
|
|---|
| 695 | // The array of values must already be allocated.
|
|---|
| 696 | static void
|
|---|
| 697 | array_from_valist (jvalue *values, JArray<jclass> *arg_types, va_list vargs)
|
|---|
| 698 | {
|
|---|
| 699 | jclass *arg_elts = elements (arg_types);
|
|---|
| 700 | for (int i = 0; i < arg_types->length; ++i)
|
|---|
| 701 | {
|
|---|
| 702 | if (arg_elts[i] == JvPrimClass (byte))
|
|---|
| 703 | values[i].b = (jbyte) va_arg (vargs, int);
|
|---|
| 704 | else if (arg_elts[i] == JvPrimClass (short))
|
|---|
| 705 | values[i].s = (jshort) va_arg (vargs, int);
|
|---|
| 706 | else if (arg_elts[i] == JvPrimClass (int))
|
|---|
| 707 | values[i].i = va_arg (vargs, jint);
|
|---|
| 708 | else if (arg_elts[i] == JvPrimClass (long))
|
|---|
| 709 | values[i].j = va_arg (vargs, jlong);
|
|---|
| 710 | else if (arg_elts[i] == JvPrimClass (float))
|
|---|
| 711 | values[i].f = va_arg (vargs, jfloat);
|
|---|
| 712 | else if (arg_elts[i] == JvPrimClass (double))
|
|---|
| 713 | values[i].d = va_arg (vargs, jdouble);
|
|---|
| 714 | else if (arg_elts[i] == JvPrimClass (boolean))
|
|---|
| 715 | values[i].z = (jboolean) va_arg (vargs, int);
|
|---|
| 716 | else if (arg_elts[i] == JvPrimClass (char))
|
|---|
| 717 | values[i].c = (jchar) va_arg (vargs, int);
|
|---|
| 718 | else
|
|---|
| 719 | {
|
|---|
| 720 | // An object.
|
|---|
| 721 | values[i].l = unwrap (va_arg (vargs, jobject));
|
|---|
| 722 | }
|
|---|
| 723 | }
|
|---|
| 724 | }
|
|---|
| 725 |
|
|---|
| 726 | // This can call any sort of method: virtual, "nonvirtual", static, or
|
|---|
| 727 | // constructor.
|
|---|
| 728 | template<typename T, invocation_type style>
|
|---|
| 729 | static T
|
|---|
| 730 | _Jv_JNI_CallAnyMethodV (JNIEnv *env, jobject obj, jclass klass,
|
|---|
| 731 | jmethodID id, va_list vargs)
|
|---|
| 732 | {
|
|---|
| 733 | obj = unwrap (obj);
|
|---|
| 734 | klass = unwrap (klass);
|
|---|
| 735 |
|
|---|
| 736 | if (style == normal)
|
|---|
| 737 | id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature);
|
|---|
| 738 |
|
|---|
| 739 | jclass decl_class = klass ? klass : obj->getClass ();
|
|---|
| 740 | JvAssert (decl_class != NULL);
|
|---|
| 741 |
|
|---|
| 742 | jclass return_type;
|
|---|
| 743 | JArray<jclass> *arg_types;
|
|---|
| 744 |
|
|---|
| 745 | try
|
|---|
| 746 | {
|
|---|
| 747 | _Jv_GetTypesFromSignature (id, decl_class,
|
|---|
| 748 | &arg_types, &return_type);
|
|---|
| 749 |
|
|---|
| 750 | jvalue args[arg_types->length];
|
|---|
| 751 | array_from_valist (args, arg_types, vargs);
|
|---|
| 752 |
|
|---|
| 753 | // For constructors we need to pass the Class we are instantiating.
|
|---|
| 754 | if (style == constructor)
|
|---|
| 755 | return_type = klass;
|
|---|
| 756 |
|
|---|
| 757 | jvalue result;
|
|---|
| 758 | jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id,
|
|---|
| 759 | style == constructor,
|
|---|
| 760 | arg_types, args, &result);
|
|---|
| 761 |
|
|---|
| 762 | if (ex != NULL)
|
|---|
| 763 | env->ex = ex;
|
|---|
| 764 |
|
|---|
| 765 | // We cheat a little here. FIXME.
|
|---|
| 766 | return wrap_value (env, * (T *) &result);
|
|---|
| 767 | }
|
|---|
| 768 | catch (jthrowable t)
|
|---|
| 769 | {
|
|---|
| 770 | env->ex = t;
|
|---|
| 771 | }
|
|---|
| 772 |
|
|---|
| 773 | return wrap_value (env, (T) 0);
|
|---|
| 774 | }
|
|---|
| 775 |
|
|---|
| 776 | template<typename T, invocation_type style>
|
|---|
| 777 | static T
|
|---|
| 778 | _Jv_JNI_CallAnyMethod (JNIEnv *env, jobject obj, jclass klass,
|
|---|
| 779 | jmethodID method, ...)
|
|---|
| 780 | {
|
|---|
| 781 | va_list args;
|
|---|
| 782 | T result;
|
|---|
| 783 |
|
|---|
| 784 | va_start (args, method);
|
|---|
| 785 | result = _Jv_JNI_CallAnyMethodV<T, style> (env, obj, klass, method, args);
|
|---|
| 786 | va_end (args);
|
|---|
| 787 |
|
|---|
| 788 | return result;
|
|---|
| 789 | }
|
|---|
| 790 |
|
|---|
| 791 | template<typename T, invocation_type style>
|
|---|
| 792 | static T
|
|---|
| 793 | _Jv_JNI_CallAnyMethodA (JNIEnv *env, jobject obj, jclass klass,
|
|---|
| 794 | jmethodID id, jvalue *args)
|
|---|
| 795 | {
|
|---|
| 796 | obj = unwrap (obj);
|
|---|
| 797 | klass = unwrap (klass);
|
|---|
| 798 |
|
|---|
| 799 | if (style == normal)
|
|---|
| 800 | id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature);
|
|---|
| 801 |
|
|---|
| 802 | jclass decl_class = klass ? klass : obj->getClass ();
|
|---|
| 803 | JvAssert (decl_class != NULL);
|
|---|
| 804 |
|
|---|
| 805 | jclass return_type;
|
|---|
| 806 | JArray<jclass> *arg_types;
|
|---|
| 807 | try
|
|---|
| 808 | {
|
|---|
| 809 | _Jv_GetTypesFromSignature (id, decl_class,
|
|---|
| 810 | &arg_types, &return_type);
|
|---|
| 811 |
|
|---|
| 812 | // For constructors we need to pass the Class we are instantiating.
|
|---|
| 813 | if (style == constructor)
|
|---|
| 814 | return_type = klass;
|
|---|
| 815 |
|
|---|
| 816 | // Unwrap arguments as required. Eww.
|
|---|
| 817 | jclass *type_elts = elements (arg_types);
|
|---|
| 818 | jvalue arg_copy[arg_types->length];
|
|---|
| 819 | for (int i = 0; i < arg_types->length; ++i)
|
|---|
| 820 | {
|
|---|
| 821 | if (type_elts[i]->isPrimitive ())
|
|---|
| 822 | arg_copy[i] = args[i];
|
|---|
| 823 | else
|
|---|
| 824 | arg_copy[i].l = unwrap (args[i].l);
|
|---|
| 825 | }
|
|---|
| 826 |
|
|---|
| 827 | jvalue result;
|
|---|
| 828 | jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id,
|
|---|
| 829 | style == constructor,
|
|---|
| 830 | arg_types, arg_copy, &result);
|
|---|
| 831 |
|
|---|
| 832 | if (ex != NULL)
|
|---|
| 833 | env->ex = ex;
|
|---|
| 834 |
|
|---|
| 835 | // We cheat a little here. FIXME.
|
|---|
| 836 | return wrap_value (env, * (T *) &result);
|
|---|
| 837 | }
|
|---|
| 838 | catch (jthrowable t)
|
|---|
| 839 | {
|
|---|
| 840 | env->ex = t;
|
|---|
| 841 | }
|
|---|
| 842 |
|
|---|
| 843 | return wrap_value (env, (T) 0);
|
|---|
| 844 | }
|
|---|
| 845 |
|
|---|
| 846 | template<invocation_type style>
|
|---|
| 847 | static void
|
|---|
| 848 | _Jv_JNI_CallAnyVoidMethodV (JNIEnv *env, jobject obj, jclass klass,
|
|---|
| 849 | jmethodID id, va_list vargs)
|
|---|
| 850 | {
|
|---|
| 851 | obj = unwrap (obj);
|
|---|
| 852 | klass = unwrap (klass);
|
|---|
| 853 |
|
|---|
| 854 | if (style == normal)
|
|---|
| 855 | id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature);
|
|---|
| 856 |
|
|---|
| 857 | jclass decl_class = klass ? klass : obj->getClass ();
|
|---|
| 858 | JvAssert (decl_class != NULL);
|
|---|
| 859 |
|
|---|
| 860 | jclass return_type;
|
|---|
| 861 | JArray<jclass> *arg_types;
|
|---|
| 862 | try
|
|---|
| 863 | {
|
|---|
| 864 | _Jv_GetTypesFromSignature (id, decl_class,
|
|---|
| 865 | &arg_types, &return_type);
|
|---|
| 866 |
|
|---|
| 867 | jvalue args[arg_types->length];
|
|---|
| 868 | array_from_valist (args, arg_types, vargs);
|
|---|
| 869 |
|
|---|
| 870 | // For constructors we need to pass the Class we are instantiating.
|
|---|
| 871 | if (style == constructor)
|
|---|
| 872 | return_type = klass;
|
|---|
| 873 |
|
|---|
| 874 | jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id,
|
|---|
| 875 | style == constructor,
|
|---|
| 876 | arg_types, args, NULL);
|
|---|
| 877 |
|
|---|
| 878 | if (ex != NULL)
|
|---|
| 879 | env->ex = ex;
|
|---|
| 880 | }
|
|---|
| 881 | catch (jthrowable t)
|
|---|
| 882 | {
|
|---|
| 883 | env->ex = t;
|
|---|
| 884 | }
|
|---|
| 885 | }
|
|---|
| 886 |
|
|---|
| 887 | template<invocation_type style>
|
|---|
| 888 | static void
|
|---|
| 889 | _Jv_JNI_CallAnyVoidMethod (JNIEnv *env, jobject obj, jclass klass,
|
|---|
| 890 | jmethodID method, ...)
|
|---|
| 891 | {
|
|---|
| 892 | va_list args;
|
|---|
| 893 |
|
|---|
| 894 | va_start (args, method);
|
|---|
| 895 | _Jv_JNI_CallAnyVoidMethodV<style> (env, obj, klass, method, args);
|
|---|
| 896 | va_end (args);
|
|---|
| 897 | }
|
|---|
| 898 |
|
|---|
| 899 | template<invocation_type style>
|
|---|
| 900 | static void
|
|---|
| 901 | _Jv_JNI_CallAnyVoidMethodA (JNIEnv *env, jobject obj, jclass klass,
|
|---|
| 902 | jmethodID id, jvalue *args)
|
|---|
| 903 | {
|
|---|
| 904 | if (style == normal)
|
|---|
| 905 | id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature);
|
|---|
| 906 |
|
|---|
| 907 | jclass decl_class = klass ? klass : obj->getClass ();
|
|---|
| 908 | JvAssert (decl_class != NULL);
|
|---|
| 909 |
|
|---|
| 910 | jclass return_type;
|
|---|
| 911 | JArray<jclass> *arg_types;
|
|---|
| 912 | try
|
|---|
| 913 | {
|
|---|
| 914 | _Jv_GetTypesFromSignature (id, decl_class,
|
|---|
| 915 | &arg_types, &return_type);
|
|---|
| 916 |
|
|---|
| 917 | // Unwrap arguments as required. Eww.
|
|---|
| 918 | jclass *type_elts = elements (arg_types);
|
|---|
| 919 | jvalue arg_copy[arg_types->length];
|
|---|
| 920 | for (int i = 0; i < arg_types->length; ++i)
|
|---|
| 921 | {
|
|---|
| 922 | if (type_elts[i]->isPrimitive ())
|
|---|
| 923 | arg_copy[i] = args[i];
|
|---|
| 924 | else
|
|---|
| 925 | arg_copy[i].l = unwrap (args[i].l);
|
|---|
| 926 | }
|
|---|
| 927 |
|
|---|
| 928 | jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id,
|
|---|
| 929 | style == constructor,
|
|---|
| 930 | arg_types, args, NULL);
|
|---|
| 931 |
|
|---|
| 932 | if (ex != NULL)
|
|---|
| 933 | env->ex = ex;
|
|---|
| 934 | }
|
|---|
| 935 | catch (jthrowable t)
|
|---|
| 936 | {
|
|---|
| 937 | env->ex = t;
|
|---|
| 938 | }
|
|---|
| 939 | }
|
|---|
| 940 |
|
|---|
| 941 | // Functions with this signature are used to implement functions in
|
|---|
| 942 | // the CallMethod family.
|
|---|
| 943 | template<typename T>
|
|---|
| 944 | static T
|
|---|
| 945 | _Jv_JNI_CallMethodV (JNIEnv *env, jobject obj, jmethodID id, va_list args)
|
|---|
| 946 | {
|
|---|
| 947 | return _Jv_JNI_CallAnyMethodV<T, normal> (env, obj, NULL, id, args);
|
|---|
| 948 | }
|
|---|
| 949 |
|
|---|
| 950 | // Functions with this signature are used to implement functions in
|
|---|
| 951 | // the CallMethod family.
|
|---|
| 952 | template<typename T>
|
|---|
| 953 | static T
|
|---|
| 954 | _Jv_JNI_CallMethod (JNIEnv *env, jobject obj, jmethodID id, ...)
|
|---|
| 955 | {
|
|---|
| 956 | va_list args;
|
|---|
| 957 | T result;
|
|---|
| 958 |
|
|---|
| 959 | va_start (args, id);
|
|---|
| 960 | result = _Jv_JNI_CallAnyMethodV<T, normal> (env, obj, NULL, id, args);
|
|---|
| 961 | va_end (args);
|
|---|
| 962 |
|
|---|
| 963 | return result;
|
|---|
| 964 | }
|
|---|
| 965 |
|
|---|
| 966 | // Functions with this signature are used to implement functions in
|
|---|
| 967 | // the CallMethod family.
|
|---|
| 968 | template<typename T>
|
|---|
| 969 | static T
|
|---|
| 970 | _Jv_JNI_CallMethodA (JNIEnv *env, jobject obj, jmethodID id, jvalue *args)
|
|---|
| 971 | {
|
|---|
| 972 | return _Jv_JNI_CallAnyMethodA<T, normal> (env, obj, NULL, id, args);
|
|---|
| 973 | }
|
|---|
| 974 |
|
|---|
| 975 | static void
|
|---|
| 976 | _Jv_JNI_CallVoidMethodV (JNIEnv *env, jobject obj, jmethodID id, va_list args)
|
|---|
| 977 | {
|
|---|
| 978 | _Jv_JNI_CallAnyVoidMethodV<normal> (env, obj, NULL, id, args);
|
|---|
| 979 | }
|
|---|
| 980 |
|
|---|
| 981 | static void
|
|---|
| 982 | _Jv_JNI_CallVoidMethod (JNIEnv *env, jobject obj, jmethodID id, ...)
|
|---|
| 983 | {
|
|---|
| 984 | va_list args;
|
|---|
| 985 |
|
|---|
| 986 | va_start (args, id);
|
|---|
| 987 | _Jv_JNI_CallAnyVoidMethodV<normal> (env, obj, NULL, id, args);
|
|---|
| 988 | va_end (args);
|
|---|
| 989 | }
|
|---|
| 990 |
|
|---|
| 991 | static void
|
|---|
| 992 | _Jv_JNI_CallVoidMethodA (JNIEnv *env, jobject obj, jmethodID id, jvalue *args)
|
|---|
| 993 | {
|
|---|
| 994 | _Jv_JNI_CallAnyVoidMethodA<normal> (env, obj, NULL, id, args);
|
|---|
| 995 | }
|
|---|
| 996 |
|
|---|
| 997 | // Functions with this signature are used to implement functions in
|
|---|
| 998 | // the CallStaticMethod family.
|
|---|
| 999 | template<typename T>
|
|---|
| 1000 | static T
|
|---|
| 1001 | _Jv_JNI_CallStaticMethodV (JNIEnv *env, jclass klass,
|
|---|
| 1002 | jmethodID id, va_list args)
|
|---|
| 1003 | {
|
|---|
| 1004 | JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
|
|---|
| 1005 | JvAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
|
|---|
| 1006 |
|
|---|
| 1007 | return _Jv_JNI_CallAnyMethodV<T, static_type> (env, NULL, klass, id, args);
|
|---|
| 1008 | }
|
|---|
| 1009 |
|
|---|
| 1010 | // Functions with this signature are used to implement functions in
|
|---|
| 1011 | // the CallStaticMethod family.
|
|---|
| 1012 | template<typename T>
|
|---|
| 1013 | static T
|
|---|
| 1014 | _Jv_JNI_CallStaticMethod (JNIEnv *env, jclass klass, jmethodID id, ...)
|
|---|
| 1015 | {
|
|---|
| 1016 | va_list args;
|
|---|
| 1017 | T result;
|
|---|
| 1018 |
|
|---|
| 1019 | JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
|
|---|
| 1020 | JvAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
|
|---|
| 1021 |
|
|---|
| 1022 | va_start (args, id);
|
|---|
| 1023 | result = _Jv_JNI_CallAnyMethodV<T, static_type> (env, NULL, klass,
|
|---|
| 1024 | id, args);
|
|---|
| 1025 | va_end (args);
|
|---|
| 1026 |
|
|---|
| 1027 | return result;
|
|---|
| 1028 | }
|
|---|
| 1029 |
|
|---|
| 1030 | // Functions with this signature are used to implement functions in
|
|---|
| 1031 | // the CallStaticMethod family.
|
|---|
| 1032 | template<typename T>
|
|---|
| 1033 | static T
|
|---|
| 1034 | _Jv_JNI_CallStaticMethodA (JNIEnv *env, jclass klass, jmethodID id,
|
|---|
| 1035 | jvalue *args)
|
|---|
| 1036 | {
|
|---|
| 1037 | JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
|
|---|
| 1038 | JvAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
|
|---|
| 1039 |
|
|---|
| 1040 | return _Jv_JNI_CallAnyMethodA<T, static_type> (env, NULL, klass, id, args);
|
|---|
| 1041 | }
|
|---|
| 1042 |
|
|---|
| 1043 | static void
|
|---|
| 1044 | _Jv_JNI_CallStaticVoidMethodV (JNIEnv *env, jclass klass, jmethodID id,
|
|---|
| 1045 | va_list args)
|
|---|
| 1046 | {
|
|---|
| 1047 | _Jv_JNI_CallAnyVoidMethodV<static_type> (env, NULL, klass, id, args);
|
|---|
| 1048 | }
|
|---|
| 1049 |
|
|---|
| 1050 | static void
|
|---|
| 1051 | _Jv_JNI_CallStaticVoidMethod (JNIEnv *env, jclass klass, jmethodID id, ...)
|
|---|
| 1052 | {
|
|---|
| 1053 | va_list args;
|
|---|
| 1054 |
|
|---|
| 1055 | va_start (args, id);
|
|---|
| 1056 | _Jv_JNI_CallAnyVoidMethodV<static_type> (env, NULL, klass, id, args);
|
|---|
| 1057 | va_end (args);
|
|---|
| 1058 | }
|
|---|
| 1059 |
|
|---|
| 1060 | static void
|
|---|
| 1061 | _Jv_JNI_CallStaticVoidMethodA (JNIEnv *env, jclass klass, jmethodID id,
|
|---|
| 1062 | jvalue *args)
|
|---|
| 1063 | {
|
|---|
| 1064 | _Jv_JNI_CallAnyVoidMethodA<static_type> (env, NULL, klass, id, args);
|
|---|
| 1065 | }
|
|---|
| 1066 |
|
|---|
| 1067 | static jobject
|
|---|
| 1068 | _Jv_JNI_NewObjectV (JNIEnv *env, jclass klass,
|
|---|
| 1069 | jmethodID id, va_list args)
|
|---|
| 1070 | {
|
|---|
| 1071 | JvAssert (klass && ! klass->isArray ());
|
|---|
| 1072 | JvAssert (! strcmp (id->name->data, "<init>")
|
|---|
| 1073 | && id->signature->length > 2
|
|---|
| 1074 | && id->signature->data[0] == '('
|
|---|
| 1075 | && ! strcmp (&id->signature->data[id->signature->length - 2],
|
|---|
| 1076 | ")V"));
|
|---|
| 1077 |
|
|---|
| 1078 | return _Jv_JNI_CallAnyMethodV<jobject, constructor> (env, NULL, klass,
|
|---|
| 1079 | id, args);
|
|---|
| 1080 | }
|
|---|
| 1081 |
|
|---|
| 1082 | static jobject
|
|---|
| 1083 | _Jv_JNI_NewObject (JNIEnv *env, jclass klass, jmethodID id, ...)
|
|---|
| 1084 | {
|
|---|
| 1085 | JvAssert (klass && ! klass->isArray ());
|
|---|
| 1086 | JvAssert (! strcmp (id->name->data, "<init>")
|
|---|
| 1087 | && id->signature->length > 2
|
|---|
| 1088 | && id->signature->data[0] == '('
|
|---|
| 1089 | && ! strcmp (&id->signature->data[id->signature->length - 2],
|
|---|
| 1090 | ")V"));
|
|---|
| 1091 |
|
|---|
| 1092 | va_list args;
|
|---|
| 1093 | jobject result;
|
|---|
| 1094 |
|
|---|
| 1095 | va_start (args, id);
|
|---|
| 1096 | result = _Jv_JNI_CallAnyMethodV<jobject, constructor> (env, NULL, klass,
|
|---|
| 1097 | id, args);
|
|---|
| 1098 | va_end (args);
|
|---|
| 1099 |
|
|---|
| 1100 | return result;
|
|---|
| 1101 | }
|
|---|
| 1102 |
|
|---|
| 1103 | static jobject
|
|---|
| 1104 | _Jv_JNI_NewObjectA (JNIEnv *env, jclass klass, jmethodID id,
|
|---|
| 1105 | jvalue *args)
|
|---|
| 1106 | {
|
|---|
| 1107 | JvAssert (klass && ! klass->isArray ());
|
|---|
| 1108 | JvAssert (! strcmp (id->name->data, "<init>")
|
|---|
| 1109 | && id->signature->length > 2
|
|---|
| 1110 | && id->signature->data[0] == '('
|
|---|
| 1111 | && ! strcmp (&id->signature->data[id->signature->length - 2],
|
|---|
| 1112 | ")V"));
|
|---|
| 1113 |
|
|---|
| 1114 | return _Jv_JNI_CallAnyMethodA<jobject, constructor> (env, NULL, klass,
|
|---|
| 1115 | id, args);
|
|---|
| 1116 | }
|
|---|
| 1117 |
|
|---|
| 1118 | |
|---|
| 1119 |
|
|---|
| 1120 |
|
|---|
| 1121 | template<typename T>
|
|---|
| 1122 | static T
|
|---|
| 1123 | _Jv_JNI_GetField (JNIEnv *env, jobject obj, jfieldID field)
|
|---|
| 1124 | {
|
|---|
| 1125 | obj = unwrap (obj);
|
|---|
| 1126 | JvAssert (obj);
|
|---|
| 1127 | T *ptr = (T *) ((char *) obj + field->getOffset ());
|
|---|
| 1128 | return wrap_value (env, *ptr);
|
|---|
| 1129 | }
|
|---|
| 1130 |
|
|---|
| 1131 | template<typename T>
|
|---|
| 1132 | static void
|
|---|
| 1133 | _Jv_JNI_SetField (JNIEnv *, jobject obj, jfieldID field, T value)
|
|---|
| 1134 | {
|
|---|
| 1135 | obj = unwrap (obj);
|
|---|
| 1136 | value = unwrap (value);
|
|---|
| 1137 |
|
|---|
| 1138 | JvAssert (obj);
|
|---|
| 1139 | T *ptr = (T *) ((char *) obj + field->getOffset ());
|
|---|
| 1140 | *ptr = value;
|
|---|
| 1141 | }
|
|---|
| 1142 |
|
|---|
| 1143 | template<jboolean is_static>
|
|---|
| 1144 | static jfieldID
|
|---|
| 1145 | _Jv_JNI_GetAnyFieldID (JNIEnv *env, jclass clazz,
|
|---|
| 1146 | const char *name, const char *sig)
|
|---|
| 1147 | {
|
|---|
| 1148 | try
|
|---|
| 1149 | {
|
|---|
| 1150 | clazz = unwrap (clazz);
|
|---|
| 1151 |
|
|---|
| 1152 | _Jv_InitClass (clazz);
|
|---|
| 1153 |
|
|---|
| 1154 | _Jv_Utf8Const *a_name = _Jv_makeUtf8Const ((char *) name, -1);
|
|---|
| 1155 |
|
|---|
| 1156 | // FIXME: assume that SIG isn't too long.
|
|---|
| 1157 | int len = strlen (sig);
|
|---|
| 1158 | char s[len + 1];
|
|---|
| 1159 | for (int i = 0; i <= len; ++i)
|
|---|
| 1160 | s[i] = (sig[i] == '/') ? '.' : sig[i];
|
|---|
| 1161 | jclass field_class = _Jv_FindClassFromSignature ((char *) s, NULL);
|
|---|
| 1162 |
|
|---|
| 1163 | // FIXME: what if field_class == NULL?
|
|---|
| 1164 |
|
|---|
| 1165 | java::lang::ClassLoader *loader = clazz->getClassLoader ();
|
|---|
| 1166 | while (clazz != NULL)
|
|---|
| 1167 | {
|
|---|
| 1168 | // We acquire the class lock so that fields aren't resolved
|
|---|
| 1169 | // while we are running.
|
|---|
| 1170 | JvSynchronize sync (clazz);
|
|---|
| 1171 |
|
|---|
| 1172 | jint count = (is_static
|
|---|
| 1173 | ? JvNumStaticFields (clazz)
|
|---|
| 1174 | : JvNumInstanceFields (clazz));
|
|---|
| 1175 | jfieldID field = (is_static
|
|---|
| 1176 | ? JvGetFirstStaticField (clazz)
|
|---|
| 1177 | : JvGetFirstInstanceField (clazz));
|
|---|
| 1178 | for (jint i = 0; i < count; ++i)
|
|---|
| 1179 | {
|
|---|
| 1180 | _Jv_Utf8Const *f_name = field->getNameUtf8Const(clazz);
|
|---|
| 1181 |
|
|---|
| 1182 | // The field might be resolved or it might not be. It
|
|---|
| 1183 | // is much simpler to always resolve it.
|
|---|
| 1184 | _Jv_ResolveField (field, loader);
|
|---|
| 1185 | if (_Jv_equalUtf8Consts (f_name, a_name)
|
|---|
| 1186 | && field->getClass() == field_class)
|
|---|
| 1187 | return field;
|
|---|
| 1188 |
|
|---|
| 1189 | field = field->getNextField ();
|
|---|
| 1190 | }
|
|---|
| 1191 |
|
|---|
| 1192 | clazz = clazz->getSuperclass ();
|
|---|
| 1193 | }
|
|---|
| 1194 |
|
|---|
| 1195 | env->ex = new java::lang::NoSuchFieldError ();
|
|---|
| 1196 | }
|
|---|
|
|---|