source: trunk/gcc/libjava/java/lang/natClass.cc

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 48.1 KB
Line 
1// natClass.cc - Implementation of java.lang.Class native methods.
2
3/* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation
4
5 This file is part of libgcj.
6
7This software is copyrighted work licensed under the terms of the
8Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9details. */
10
11#include <config.h>
12
13#include <limits.h>
14#include <string.h>
15
16#pragma implementation "Class.h"
17
18#include <gcj/cni.h>
19#include <jvm.h>
20#include <java-threads.h>
21
22#include <java/lang/Class.h>
23#include <java/lang/ClassLoader.h>
24#include <java/lang/String.h>
25#include <java/lang/reflect/Modifier.h>
26#include <java/lang/reflect/Member.h>
27#include <java/lang/reflect/Method.h>
28#include <java/lang/reflect/Field.h>
29#include <java/lang/reflect/Constructor.h>
30#include <java/lang/AbstractMethodError.h>
31#include <java/lang/ArrayStoreException.h>
32#include <java/lang/ClassCastException.h>
33#include <java/lang/ClassNotFoundException.h>
34#include <java/lang/ExceptionInInitializerError.h>
35#include <java/lang/IllegalAccessException.h>
36#include <java/lang/IllegalAccessError.h>
37#include <java/lang/IllegalArgumentException.h>
38#include <java/lang/IncompatibleClassChangeError.h>
39#include <java/lang/ArrayIndexOutOfBoundsException.h>
40#include <java/lang/InstantiationException.h>
41#include <java/lang/NoClassDefFoundError.h>
42#include <java/lang/NoSuchFieldException.h>
43#include <java/lang/NoSuchMethodError.h>
44#include <java/lang/NoSuchMethodException.h>
45#include <java/lang/Thread.h>
46#include <java/lang/NullPointerException.h>
47#include <java/lang/RuntimePermission.h>
48#include <java/lang/System.h>
49#include <java/lang/SecurityManager.h>
50#include <java/lang/StringBuffer.h>
51#include <gnu/gcj/runtime/StackTrace.h>
52#include <gcj/method.h>
53#include <gnu/gcj/runtime/MethodRef.h>
54#include <gnu/gcj/RawData.h>
55
56#include <java-cpool.h>
57
58
59
60
61using namespace gcj;
62
63jclass
64java::lang::Class::forName (jstring className, jboolean initialize,
65 java::lang::ClassLoader *loader)
66{
67 if (! className)
68 throw new java::lang::NullPointerException;
69
70 jsize length = _Jv_GetStringUTFLength (className);
71 char buffer[length];
72 _Jv_GetStringUTFRegion (className, 0, length, buffer);
73
74 _Jv_Utf8Const *name = _Jv_makeUtf8Const (buffer, length);
75
76 if (! _Jv_VerifyClassName (name))
77 throw new java::lang::ClassNotFoundException (className);
78
79 jclass klass = (buffer[0] == '['
80 ? _Jv_FindClassFromSignature (name->data, loader)
81 : _Jv_FindClass (name, loader));
82
83 if (klass == NULL)
84 throw new java::lang::ClassNotFoundException (className);
85
86 if (initialize)
87 _Jv_InitClass (klass);
88
89 return klass;
90}
91
92jclass
93java::lang::Class::forName (jstring className)
94{
95 java::lang::ClassLoader *loader = NULL;
96 gnu::gcj::runtime::StackTrace *t
97 = new gnu::gcj::runtime::StackTrace(4);
98 java::lang::Class *klass = NULL;
99 try
100 {
101 for (int i = 1; !klass; i++)
102 {
103 klass = t->classAt (i);
104 }
105 loader = klass->getClassLoader();
106 }
107 catch (::java::lang::ArrayIndexOutOfBoundsException *e)
108 {
109 }
110
111 return forName (className, true, loader);
112}
113
114java::lang::ClassLoader *
115java::lang::Class::getClassLoader (void)
116{
117#if 0
118 // FIXME: the checks we need to do are more complex. See the spec.
119 // Currently we can't implement them.
120 java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
121 if (s != NULL)
122 s->checkPermission (new RuntimePermission (JvNewStringLatin1 ("getClassLoader")));
123#endif
124
125 // The spec requires us to return `null' for primitive classes. In
126 // other cases we have the option of returning `null' for classes
127 // loaded with the bootstrap loader. All gcj-compiled classes which
128 // are linked into the application used to return `null' here, but
129 // that confuses some poorly-written applications. It is a useful
130 // and apparently harmless compatibility hack to simply never return
131 // `null' instead.
132 if (isPrimitive ())
133 return NULL;
134 return loader ? loader : ClassLoader::getSystemClassLoader ();
135}
136
137java::lang::reflect::Constructor *
138java::lang::Class::getConstructor (JArray<jclass> *param_types)
139{
140 jstring partial_sig = getSignature (param_types, true);
141 jint hash = partial_sig->hashCode ();
142
143 int i = isPrimitive () ? 0 : method_count;
144 while (--i >= 0)
145 {
146 // FIXME: access checks.
147 if (_Jv_equalUtf8Consts (methods[i].name, init_name)
148 && _Jv_equal (methods[i].signature, partial_sig, hash))
149 {
150 // Found it. For getConstructor, the constructor must be
151 // public.
152 using namespace java::lang::reflect;
153 if (! Modifier::isPublic(methods[i].accflags))
154 break;
155 Constructor *cons = new Constructor ();
156 cons->offset = (char *) (&methods[i]) - (char *) methods;
157 cons->declaringClass = this;
158 return cons;
159 }
160 }
161 throw new java::lang::NoSuchMethodException;
162}
163
164JArray<java::lang::reflect::Constructor *> *
165java::lang::Class::_getConstructors (jboolean declared)
166{
167 // FIXME: this method needs access checks.
168
169 int numConstructors = 0;
170 int max = isPrimitive () ? 0 : method_count;
171 int i;
172 for (i = max; --i >= 0; )
173 {
174 _Jv_Method *method = &methods[i];
175 if (method->name == NULL
176 || ! _Jv_equalUtf8Consts (method->name, init_name))
177 continue;
178 if (! declared
179 && ! java::lang::reflect::Modifier::isPublic(method->accflags))
180 continue;
181 numConstructors++;
182 }
183 JArray<java::lang::reflect::Constructor *> *result
184 = (JArray<java::lang::reflect::Constructor *> *)
185 JvNewObjectArray (numConstructors,
186 &java::lang::reflect::Constructor::class$,
187 NULL);
188 java::lang::reflect::Constructor** cptr = elements (result);
189 for (i = 0; i < max; i++)
190 {
191 _Jv_Method *method = &methods[i];
192 if (method->name == NULL
193 || ! _Jv_equalUtf8Consts (method->name, init_name))
194 continue;
195 if (! declared
196 && ! java::lang::reflect::Modifier::isPublic(method->accflags))
197 continue;
198 java::lang::reflect::Constructor *cons
199 = new java::lang::reflect::Constructor ();
200 cons->offset = (char *) method - (char *) methods;
201 cons->declaringClass = this;
202 *cptr++ = cons;
203 }
204 return result;
205}
206
207java::lang::reflect::Constructor *
208java::lang::Class::getDeclaredConstructor (JArray<jclass> *param_types)
209{
210 jstring partial_sig = getSignature (param_types, true);
211 jint hash = partial_sig->hashCode ();
212
213 int i = isPrimitive () ? 0 : method_count;
214 while (--i >= 0)
215 {
216 // FIXME: access checks.
217 if (_Jv_equalUtf8Consts (methods[i].name, init_name)
218 && _Jv_equal (methods[i].signature, partial_sig, hash))
219 {
220 // Found it.
221 using namespace java::lang::reflect;
222 Constructor *cons = new Constructor ();
223 cons->offset = (char *) (&methods[i]) - (char *) methods;
224 cons->declaringClass = this;
225 return cons;
226 }
227 }
228 throw new java::lang::NoSuchMethodException;
229}
230
231java::lang::reflect::Field *
232java::lang::Class::getField (jstring name, jint hash)
233{
234 java::lang::reflect::Field* rfield;
235 for (int i = 0; i < field_count; i++)
236 {
237 _Jv_Field *field = &fields[i];
238 if (! _Jv_equal (field->name, name, hash))
239 continue;
240 if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
241 continue;
242 rfield = new java::lang::reflect::Field ();
243 rfield->offset = (char*) field - (char*) fields;
244 rfield->declaringClass = this;
245 rfield->name = name;
246 return rfield;
247 }
248 jclass superclass = getSuperclass();
249 if (superclass == NULL)
250 return NULL;
251 rfield = superclass->getField(name, hash);
252 for (int i = 0; i < interface_count && rfield == NULL; ++i)
253 rfield = interfaces[i]->getField (name, hash);
254 return rfield;
255}
256
257java::lang::reflect::Field *
258java::lang::Class::getDeclaredField (jstring name)
259{
260 java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
261 if (s != NULL)
262 s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
263 int hash = name->hashCode();
264 for (int i = 0; i < field_count; i++)
265 {
266 _Jv_Field *field = &fields[i];
267 if (! _Jv_equal (field->name, name, hash))
268 continue;
269 java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
270 rfield->offset = (char*) field - (char*) fields;
271 rfield->declaringClass = this;
272 rfield->name = name;
273 return rfield;
274 }
275 throw new java::lang::NoSuchFieldException (name);
276}
277
278JArray<java::lang::reflect::Field *> *
279java::lang::Class::getDeclaredFields (void)
280{
281 java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
282 if (s != NULL)
283 s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
284 JArray<java::lang::reflect::Field *> *result
285 = (JArray<java::lang::reflect::Field *> *)
286 JvNewObjectArray (field_count, &java::lang::reflect::Field::class$, NULL);
287 java::lang::reflect::Field** fptr = elements (result);
288 for (int i = 0; i < field_count; i++)
289 {
290 _Jv_Field *field = &fields[i];
291 java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
292 rfield->offset = (char*) field - (char*) fields;
293 rfield->declaringClass = this;
294 *fptr++ = rfield;
295 }
296 return result;
297}
298
299void
300java::lang::Class::getSignature (java::lang::StringBuffer *buffer)
301{
302 if (isPrimitive())
303 buffer->append((jchar) method_count);
304 else
305 {
306 jstring name = getName();
307 if (name->charAt(0) != '[')
308 buffer->append((jchar) 'L');
309 buffer->append(name);
310 if (name->charAt(0) != '[')
311 buffer->append((jchar) ';');
312 }
313}
314
315// This doesn't have to be native. It is an implementation detail
316// only called from the C++ code, though, so maybe this is clearer.
317jstring
318java::lang::Class::getSignature (JArray<jclass> *param_types,
319 jboolean is_constructor)
320{
321 java::lang::StringBuffer *buf = new java::lang::StringBuffer ();
322 buf->append((jchar) '(');
323 // A NULL param_types means "no parameters".
324 if (param_types != NULL)
325 {
326 jclass *v = elements (param_types);
327 for (int i = 0; i < param_types->length; ++i)
328 v[i]->getSignature(buf);
329 }
330 buf->append((jchar) ')');
331 if (is_constructor)
332 buf->append((jchar) 'V');
333 return buf->toString();
334}
335
336java::lang::reflect::Method *
337java::lang::Class::_getDeclaredMethod (jstring name,
338 JArray<jclass> *param_types)
339{
340 jstring partial_sig = getSignature (param_types, false);
341 jint p_len = partial_sig->length();
342 _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
343 int i = isPrimitive () ? 0 : method_count;
344 while (--i >= 0)
345 {
346 if (_Jv_equalUtf8Consts (methods[i].name, utf_name)
347 && _Jv_equaln (methods[i].signature, partial_sig, p_len)
348 && (methods[i].accflags
349 & java::lang::reflect::Modifier::INVISIBLE) == 0)
350 {
351 // Found it.
352 using namespace java::lang::reflect;
353 Method *rmethod = new Method ();
354 rmethod->offset = (char*) (&methods[i]) - (char*) methods;
355 rmethod->declaringClass = this;
356 return rmethod;
357 }
358 }
359 return NULL;
360}
361
362JArray<java::lang::reflect::Method *> *
363java::lang::Class::getDeclaredMethods (void)
364{
365 int numMethods = 0;
366 int max = isPrimitive () ? 0 : method_count;
367 int i;
368 for (i = max; --i >= 0; )
369 {
370 _Jv_Method *method = &methods[i];
371 if (method->name == NULL
372 || _Jv_equalUtf8Consts (method->name, clinit_name)
373 || _Jv_equalUtf8Consts (method->name, init_name)
374 || _Jv_equalUtf8Consts (method->name, finit_name)
375 || (methods[i].accflags
376 & java::lang::reflect::Modifier::INVISIBLE) != 0)
377 continue;
378 numMethods++;
379 }
380 JArray<java::lang::reflect::Method *> *result
381 = (JArray<java::lang::reflect::Method *> *)
382 JvNewObjectArray (numMethods, &java::lang::reflect::Method::class$, NULL);
383 java::lang::reflect::Method** mptr = elements (result);
384 for (i = 0; i < max; i++)
385 {
386 _Jv_Method *method = &methods[i];
387 if (method->name == NULL
388 || _Jv_equalUtf8Consts (method->name, clinit_name)
389 || _Jv_equalUtf8Consts (method->name, init_name)
390 || _Jv_equalUtf8Consts (method->name, finit_name)
391 || (methods[i].accflags
392 & java::lang::reflect::Modifier::INVISIBLE) != 0)
393 continue;
394 java::lang::reflect::Method* rmethod
395 = new java::lang::reflect::Method ();
396 rmethod->offset = (char*) method - (char*) methods;
397 rmethod->declaringClass = this;
398 *mptr++ = rmethod;
399 }
400 return result;
401}
402
403jstring
404java::lang::Class::getName (void)
405{
406 char buffer[name->length + 1];
407 memcpy (buffer, name->data, name->length);
408 buffer[name->length] = '\0';
409 return _Jv_NewStringUTF (buffer);
410}
411
412JArray<jclass> *
413java::lang::Class::getClasses (void)
414{
415 // FIXME: security checking.
416
417 // Until we have inner classes, it always makes sense to return an
418 // empty array.
419 JArray<jclass> *result
420 = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$,
421 NULL);
422 return result;
423}
424
425JArray<jclass> *
426java::lang::Class::getDeclaredClasses (void)
427{
428 checkMemberAccess (java::lang::reflect::Member::DECLARED);
429 // Until we have inner classes, it always makes sense to return an
430 // empty array.
431 JArray<jclass> *result
432 = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$,
433 NULL);
434 return result;
435}
436
437jclass
438java::lang::Class::getDeclaringClass (void)
439{
440 // Until we have inner classes, it makes sense to always return
441 // NULL.
442 return NULL;
443}
444
445jint
446java::lang::Class::_getFields (JArray<java::lang::reflect::Field *> *result,
447 jint offset)
448{
449 int count = 0;
450 for (int i = 0; i < field_count; i++)
451 {
452 _Jv_Field *field = &fields[i];
453 if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
454 continue;
455 ++count;
456
457 if (result != NULL)
458 {
459 java::lang::reflect::Field *rfield
460 = new java::lang::reflect::Field ();
461 rfield->offset = (char *) field - (char *) fields;
462 rfield->declaringClass = this;
463 rfield->name = _Jv_NewStringUtf8Const (field->name);
464 (elements (result))[offset++] = rfield;
465 }
466 }
467 jclass superclass = getSuperclass();
468 if (superclass != NULL)
469 {
470 int s_count = superclass->_getFields (result, offset);
471 count += s_count;
472 offset += s_count;
473 }
474 for (int i = 0; i < interface_count; ++i)
475 {
476 int f_count = interfaces[i]->_getFields (result, offset);
477 count += f_count;
478 offset += f_count;
479 }
480 return count;
481}
482
483JArray<java::lang::reflect::Field *> *
484java::lang::Class::getFields (void)
485{
486 // FIXME: security checking.
487
488 using namespace java::lang::reflect;
489
490 int count = _getFields (NULL, 0);
491
492 JArray<java::lang::reflect::Field *> *result
493 = ((JArray<java::lang::reflect::Field *> *)
494 JvNewObjectArray (count, &java::lang::reflect::Field::class$, NULL));
495
496 _getFields (result, 0);
497
498 return result;
499}
500
501JArray<jclass> *
502java::lang::Class::getInterfaces (void)
503{
504 jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL);
505 jobject *data = elements (r);
506 for (int i = 0; i < interface_count; ++i)
507 data[i] = interfaces[i];
508 return reinterpret_cast<JArray<jclass> *> (r);
509}
510
511java::lang::reflect::Method *
512java::lang::Class::_getMethod (jstring name, JArray<jclass> *param_types)
513{
514 jstring partial_sig = getSignature (param_types, false);
515 jint p_len = partial_sig->length();
516 _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
517 for (Class *klass = this; klass; klass = klass->getSuperclass())
518 {
519 int i = klass->isPrimitive () ? 0 : klass->method_count;
520 while (--i >= 0)
521 {
522 // FIXME: access checks.
523 if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
524 && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len)
525 && (klass->methods[i].accflags
526 & java::lang::reflect::Modifier::INVISIBLE) == 0)
527 {
528 // Found it.
529 using namespace java::lang::reflect;
530
531 // Method must be public.
532 if (! Modifier::isPublic (klass->methods[i].accflags))
533 break;
534
535 Method *rmethod = new Method ();
536 rmethod->offset = ((char *) (&klass->methods[i])
537 - (char *) klass->methods);
538 rmethod->declaringClass = klass;
539 return rmethod;
540 }
541 }
542 }
543
544 // If we haven't found a match, and this class is an interface, then
545 // check all the superinterfaces.
546 if (isInterface())
547 {
548 for (int i = 0; i < interface_count; ++i)
549 {
550 using namespace java::lang::reflect;
551 Method *rmethod = interfaces[i]->_getMethod (name, param_types);
552 if (rmethod != NULL)
553 return rmethod;
554 }
555 }
556
557 return NULL;
558}
559
560// This is a very slow implementation, since it re-scans all the
561// methods we've already listed to make sure we haven't duplicated a
562// method. It also over-estimates the required size, so we have to
563// shrink the result array later.
564jint
565java::lang::Class::_getMethods (JArray<java::lang::reflect::Method *> *result,
566 jint offset)
567{
568 jint count = 0;
569
570 // First examine all local methods
571 for (int i = isPrimitive () ? 0 : method_count; --i >= 0; )
572 {
573 _Jv_Method *method = &methods[i];
574 if (method->name == NULL
575 || _Jv_equalUtf8Consts (method->name, clinit_name)
576 || _Jv_equalUtf8Consts (method->name, init_name)
577 || _Jv_equalUtf8Consts (method->name, finit_name)
578 || (method->accflags
579 & java::lang::reflect::Modifier::INVISIBLE) != 0)
580 continue;
581 // Only want public methods.
582 if (! java::lang::reflect::Modifier::isPublic (method->accflags))
583 continue;
584
585 // This is where we over-count the slots required if we aren't
586 // filling the result for real.
587 if (result != NULL)
588 {
589 jboolean add = true;
590 java::lang::reflect::Method **mp = elements (result);
591 // If we already have a method with this name and signature,
592 // then ignore this one. This can happen with virtual
593 // methods.
594 for (int j = 0; j < offset; ++j)
595 {
596 _Jv_Method *meth_2 = _Jv_FromReflectedMethod (mp[j]);
597 if (_Jv_equalUtf8Consts (method->name, meth_2->name)
598 && _Jv_equalUtf8Consts (method->signature,
599 meth_2->signature))
600 {
601 add = false;
602 break;
603 }
604 }
605 if (! add)
606 continue;
607 }
608
609 if (result != NULL)
610 {
611 using namespace java::lang::reflect;
612 Method *rmethod = new Method ();
613 rmethod->offset = (char *) method - (char *) methods;
614 rmethod->declaringClass = this;
615 Method **mp = elements (result);
616 mp[offset + count] = rmethod;
617 }
618 ++count;
619 }
620 offset += count;
621
622 // Now examine superclasses.
623 if (getSuperclass () != NULL)
624 {
625 jint s_count = getSuperclass()->_getMethods (result, offset);
626 offset += s_count;
627 count += s_count;
628 }
629
630 // Finally, examine interfaces.
631 for (int i = 0; i < interface_count; ++i)
632 {
633 int f_count = interfaces[i]->_getMethods (result, offset);
634 count += f_count;
635 offset += f_count;
636 }
637
638 return count;
639}
640
641JArray<java::lang::reflect::Method *> *
642java::lang::Class::getMethods (void)
643{
644 using namespace java::lang::reflect;
645
646 // FIXME: security checks.
647
648 // This will overestimate the size we need.
649 jint count = _getMethods (NULL, 0);
650
651 JArray<Method *> *result
652 = ((JArray<Method *> *) JvNewObjectArray (count,
653 &Method::class$,
654 NULL));
655
656 // When filling the array for real, we get the actual count. Then
657 // we resize the array.
658 jint real_count = _getMethods (result, 0);
659
660 if (real_count != count)
661 {
662 JArray<Method *> *r2
663 = ((JArray<Method *> *) JvNewObjectArray (real_count,
664 &Method::class$,
665 NULL));
666
667 Method **destp = elements (r2);
668 Method **srcp = elements (result);
669
670 for (int i = 0; i < real_count; ++i)
671 *destp++ = *srcp++;
672
673 result = r2;
674 }
675
676 return result;
677}
678
679jboolean
680java::lang::Class::isAssignableFrom (jclass klass)
681{
682 // Arguments may not have been initialized, given ".class" syntax.
683 _Jv_InitClass (this);
684 _Jv_InitClass (klass);
685 return _Jv_IsAssignableFrom (this, klass);
686}
687
688jboolean
689java::lang::Class::isInstance (jobject obj)
690{
691 if (! obj)
692 return false;
693 _Jv_InitClass (this);
694 return _Jv_IsAssignableFrom (this, JV_CLASS (obj));
695}
696
697jobject
698java::lang::Class::newInstance (void)
699{
700 // FIXME: do accessibility checks here. There currently doesn't
701 // seem to be any way to do these.
702 // FIXME: we special-case one check here just to pass a Plum Hall
703 // test. Once access checking is implemented, remove this.
704 if (this == &java::lang::Class::class$)
705 throw new java::lang::IllegalAccessException;
706
707 if (isPrimitive ()
708 || isInterface ()
709 || isArray ()
710 || java::lang::reflect::Modifier::isAbstract(accflags))
711 throw new java::lang::InstantiationException;
712
713 _Jv_InitClass (this);
714
715 _Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature);
716 if (! meth)
717 throw new java::lang::NoSuchMethodException;
718
719 jobject r = JvAllocObject (this);
720 ((void (*) (jobject)) meth->ncode) (r);
721 return r;
722}
723
724void
725java::lang::Class::finalize (void)
726{
727#ifdef INTERPRETER
728 JvAssert (_Jv_IsInterpretedClass (this));
729 _Jv_UnregisterClass (this);
730#endif
731}
732
733// This implements the initialization process for a class. From Spec
734// section 12.4.2.
735void
736java::lang::Class::initializeClass (void)
737{
738 // short-circuit to avoid needless locking.
739 if (state == JV_STATE_DONE)
740 return;
741
742 // Step 1.
743 _Jv_MonitorEnter (this);
744
745 if (state < JV_STATE_LINKED)
746 {
747#ifdef INTERPRETER
748 if (_Jv_IsInterpretedClass (this))
749 {
750 // this can throw exceptions, so exit the monitor as a precaution.
751 _Jv_MonitorExit (this);
752 java::lang::ClassLoader::resolveClass0 (this);
753 _Jv_MonitorEnter (this);
754 }
755 else
756#endif
757 {
758 _Jv_PrepareCompiledClass (this);
759 }
760 }
761
762 if (state <= JV_STATE_LINKED)
763 _Jv_PrepareConstantTimeTables (this);
764
765 // Step 2.
766 java::lang::Thread *self = java::lang::Thread::currentThread();
767 // FIXME: `self' can be null at startup. Hence this nasty trick.
768 self = (java::lang::Thread *) ((long) self | 1);
769 while (state == JV_STATE_IN_PROGRESS && thread && thread != self)
770 wait ();
771
772 // Steps 3 & 4.
773 if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS)
774 {
775 _Jv_MonitorExit (this);
776 return;
777 }
778
779 // Step 5.
780 if (state == JV_STATE_ERROR)
781 {
782 _Jv_MonitorExit (this);
783 throw new java::lang::NoClassDefFoundError (getName());
784 }
785
786 // Step 6.
787 thread = self;
788 state = JV_STATE_IN_PROGRESS;
789 _Jv_MonitorExit (this);
790
791 // Step 7.
792 if (! isInterface () && superclass)
793 {
794 try
795 {
796 _Jv_InitClass (superclass);
797 }
798 catch (java::lang::Throwable *except)
799 {
800 // Caught an exception.
801 _Jv_MonitorEnter (this);
802 state = JV_STATE_ERROR;
803 notifyAll ();
804 _Jv_MonitorExit (this);
805 throw except;
806 }
807 }
808
809 // Steps 8, 9, 10, 11.
810 try
811 {
812 _Jv_Method *meth = _Jv_GetMethodLocal (this, clinit_name,
813 void_signature);
814 if (meth)
815 ((void (*) (void)) meth->ncode) ();
816 }
817 catch (java::lang::Throwable *except)
818 {
819 if (! java::lang::Error::class$.isInstance(except))
820 {
821 try
822 {
823 except = new ExceptionInInitializerError (except);
824 }
825 catch (java::lang::Throwable *t)
826 {
827 except = t;
828 }
829 }
830 _Jv_MonitorEnter (this);
831 state = JV_STATE_ERROR;
832 notifyAll ();
833 _Jv_MonitorExit (this);
834 throw except;
835 }
836
837 _Jv_MonitorEnter (this);
838 state = JV_STATE_DONE;
839 notifyAll ();
840 _Jv_MonitorExit (this);
841}
842
843
844
845
846//
847// Some class-related convenience functions.
848//
849
850// Find a method declared in the class. If it is not declared locally
851// (or if it is inherited), return NULL.
852_Jv_Method *
853_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name,
854 _Jv_Utf8Const *signature)
855{
856 for (int i = 0; i < klass->method_count; ++i)
857 {
858 if (_Jv_equalUtf8Consts (name, klass->methods[i].name)
859 && _Jv_equalUtf8Consts (signature, klass->methods[i].signature))
860 return &klass->methods[i];
861 }
862 return NULL;
863}
864
865_Jv_Method *
866_Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name,
867 _Jv_Utf8Const *signature)
868{
869 for (; klass; klass = klass->getSuperclass())
870 {
871 _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
872
873 if (meth)
874 return meth;
875 }
876
877 return NULL;
878}
879
880// NOTE: MCACHE_SIZE should be a power of 2 minus one.
881#define MCACHE_SIZE 1023
882
883struct _Jv_mcache
884{
885 jclass klass;
886 _Jv_Method *method;
887};
888
889static _Jv_mcache method_cache[MCACHE_SIZE + 1];
890
891static void *
892_Jv_FindMethodInCache (jclass klass,
893 _Jv_Utf8Const *name,
894 _Jv_Utf8Const *signature)
895{
896 int index = name->hash & MCACHE_SIZE;
897 _Jv_mcache *mc = method_cache + index;
898 _Jv_Method *m = mc->method;
899
900 if (mc->klass == klass
901 && m != NULL // thread safe check
902 && _Jv_equalUtf8Consts (m->name, name)
903 && _Jv_equalUtf8Consts (m->signature, signature))
904 return mc->method->ncode;
905 return NULL;
906}
907
908static void
909_Jv_AddMethodToCache (jclass klass,
910 _Jv_Method *method)
911{
912 _Jv_MonitorEnter (&java::lang::Class::class$);
913
914 int index = method->name->hash & MCACHE_SIZE;
915
916 method_cache[index].method = method;
917 method_cache[index].klass = klass;
918
919 _Jv_MonitorExit (&java::lang::Class::class$);
920}
921
922void *
923_Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name,
924 _Jv_Utf8Const *signature)
925{
926 using namespace java::lang::reflect;
927
928 void *ncode = _Jv_FindMethodInCache (klass, name, signature);
929 if (ncode != 0)
930 return ncode;
931
932 for (; klass; klass = klass->getSuperclass())
933 {
934 _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
935 if (! meth)
936 continue;
937
938 if (Modifier::isStatic(meth->accflags))
939 throw new java::lang::IncompatibleClassChangeError
940 (_Jv_GetMethodString (klass, meth->name));
941 if (Modifier::isAbstract(meth->accflags))
942 throw new java::lang::AbstractMethodError
943 (_Jv_GetMethodString (klass, meth->name));
944 if (! Modifier::isPublic(meth->accflags))
945 throw new java::lang::IllegalAccessError
946 (_Jv_GetMethodString (klass, meth->name));
947
948 _Jv_AddMethodToCache (klass, meth);
949
950 return meth->ncode;
951 }
952 throw new java::lang::IncompatibleClassChangeError;
953}
954
955// Fast interface method lookup by index.
956void *
957_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx)
958{
959 _Jv_IDispatchTable *cldt = klass->idt;
960 int idx = iface->idt->iface.ioffsets[cldt->cls.iindex] + method_idx;
961 return cldt->cls.itable[idx];
962}
963
964jboolean
965_Jv_IsAssignableFrom (jclass target, jclass source)
966{
967 if (source == target)
968 return true;
969
970 // If target is array, so must source be.
971 while (target->isArray ())
972 {
973 if (! source->isArray())
974 return false;
975 target = target->getComponentType();
976 source = source->getComponentType();
977 }
978
979 if (target->isInterface())
980 {
981 // Abstract classes have no IDT, and IDTs provide no way to check
982 // two interfaces for assignability.
983 if (__builtin_expect
984 (source->idt == NULL || source->isInterface(), false))
985 return _Jv_InterfaceAssignableFrom (target, source);
986
987 _Jv_IDispatchTable *cl_idt = source->idt;
988 _Jv_IDispatchTable *if_idt = target->idt;
989
990 if (__builtin_expect ((if_idt == NULL), false))
991 return false; // No class implementing TARGET has been loaded.
992 jshort cl_iindex = cl_idt->cls.iindex;
993 if (cl_iindex < if_idt->iface.ioffsets[0])
994 {
995 jshort offset = if_idt->iface.ioffsets[cl_iindex];
996 if (offset != -1 && offset < cl_idt->cls.itable_length
997 && cl_idt->cls.itable[offset] == target)
998 return true;
999 }
1000 return false;
1001 }
1002
1003 // Primitive TYPE classes are only assignable to themselves.
1004 if (__builtin_expect (target->isPrimitive() || source->isPrimitive(), false))
1005 return false;
1006
1007 if (target == &java::lang::Object::class$)
1008 return true;
1009 else if (source->ancestors == NULL || target->ancestors == NULL)
1010 {
1011 // We need this case when either SOURCE or TARGET has not has
1012 // its constant-time tables prepared.
1013
1014 // At this point we know that TARGET can't be Object, so it is
1015 // safe to use that as the termination point.
1016 while (source && source != &java::lang::Object::class$)
1017 {
1018 if (source == target)
1019 return true;
1020 source = source->getSuperclass();
1021 }
1022 }
1023 else if (source->depth >= target->depth
1024 && source->ancestors[source->depth - target->depth] == target)
1025 return true;
1026
1027 return false;
1028}
1029
1030// Interface type checking, the slow way. Returns TRUE if IFACE is a
1031// superinterface of SOURCE. This is used when SOURCE is also an interface,
1032// or a class with no interface dispatch table.
1033jboolean
1034_Jv_InterfaceAssignableFrom (jclass iface, jclass source)
1035{
1036 for (int i = 0; i < source->interface_count; i++)
1037 {
1038 jclass interface = source->interfaces[i];
1039 if (iface == interface
1040 || _Jv_InterfaceAssignableFrom (iface, interface))
1041 return true;
1042 }
1043
1044 if (!source->isInterface()
1045 && source->superclass
1046 && _Jv_InterfaceAssignableFrom (iface, source->superclass))
1047 return true;
1048
1049 return false;
1050}
1051
1052jboolean
1053_Jv_IsInstanceOf(jobject obj, jclass cl)
1054{
1055 if (__builtin_expect (!obj, false))
1056 return false;
1057 return (_Jv_IsAssignableFrom (cl, JV_CLASS (obj)));
1058}
1059
1060void *
1061_Jv_CheckCast (jclass c, jobject obj)
1062{
1063 if (__builtin_expect
1064 (obj != NULL && ! _Jv_IsAssignableFrom(c, JV_CLASS (obj)), false))
1065 throw new java::lang::ClassCastException
1066 ((new java::lang::StringBuffer
1067 (obj->getClass()->getName()))->append
1068 (JvNewStringUTF(" cannot be cast to "))->append
1069 (c->getName())->toString());
1070
1071 return obj;
1072}
1073
1074void
1075_Jv_CheckArrayStore (jobject arr, jobject obj)
1076{
1077 if (obj)
1078 {
1079 JvAssert (arr != NULL);
1080 jclass elt_class = (JV_CLASS (arr))->getComponentType();
1081 if (elt_class == &java::lang::Object::class$)
1082 return;
1083 jclass obj_class = JV_CLASS (obj);
1084 if (__builtin_expect
1085 (! _Jv_IsAssignableFrom (elt_class, obj_class), false))
1086 throw new java::lang::ArrayStoreException
1087 ((new java::lang::StringBuffer
1088 (JvNewStringUTF("Cannot store ")))->append
1089 (obj_class->getName())->append
1090 (JvNewStringUTF(" in array of type "))->append
1091 (elt_class->getName())->toString());
1092 }
1093}
1094
1095#define INITIAL_IOFFSETS_LEN 4
1096#define INITIAL_IFACES_LEN 4
1097
1098static _Jv_IDispatchTable null_idt = { {SHRT_MAX, 0, NULL} };
1099
1100// Generate tables for constant-time assignment testing and interface
1101// method lookup. This implements the technique described by Per Bothner
1102// <per@bothner.com> on the java-discuss mailing list on 1999-09-02:
1103// http://gcc.gnu.org/ml/java/1999-q3/msg00377.html
1104void
1105_Jv_PrepareConstantTimeTables (jclass klass)
1106{
1107 if (klass->isPrimitive () || klass->isInterface ())
1108 return;
1109
1110 // Short-circuit in case we've been called already.
1111 if ((klass->idt != NULL) || klass->depth != 0)
1112 return;
1113
1114 // Calculate the class depth and ancestor table. The depth of a class
1115 // is how many "extends" it is removed from Object. Thus the depth of
1116 // java.lang.Object is 0, but the depth of java.io.FilterOutputStream
1117 // is 2. Depth is defined for all regular and array classes, but not
1118 // interfaces or primitive types.
1119
1120 jclass klass0 = klass;
1121 jboolean has_interfaces = 0;
1122 while (klass0 != &java::lang::Object::class$)
1123 {
1124 has_interfaces += klass0->interface_count;
1125 klass0 = klass0->superclass;
1126 klass->depth++;
1127 }
1128
1129 // We do class member testing in constant time by using a small table
1130 // of all the ancestor classes within each class. The first element is
1131 // a pointer to the current class, and the rest are pointers to the
1132 // classes ancestors, ordered from the current class down by decreasing
1133 // depth. We do not include java.lang.Object in the table of ancestors,
1134 // since it is redundant.
1135
1136 klass->ancestors = (jclass *) _Jv_Malloc (klass->depth * sizeof (jclass));
1137 klass0 = klass;
1138 for (int index = 0; index < klass->depth; index++)
1139 {
1140 klass->ancestors[index] = klass0;
1141 klass0 = klass0->superclass;
1142 }
1143
1144 if (java::lang::reflect::Modifier::isAbstract (klass->accflags))
1145 return;
1146
1147 // Optimization: If class implements no interfaces, use a common
1148 // predefined interface table.
1149 if (!has_interfaces)
1150 {
1151 klass->idt = &null_idt;
1152 return;
1153 }
1154
1155 klass->idt =
1156 (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
1157
1158 _Jv_ifaces ifaces;
1159
1160 ifaces.count = 0;
1161 ifaces.len = INITIAL_IFACES_LEN;
1162 ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *));
1163
1164 int itable_size = _Jv_GetInterfaces (klass, &ifaces);
1165
1166 if (ifaces.count > 0)
1167 {
1168 klass->idt->cls.itable =
1169 (void **) _Jv_Malloc (itable_size * sizeof (void *));
1170 klass->idt->cls.itable_length = itable_size;
1171
1172 jshort *itable_offsets =
1173 (jshort *) _Jv_Malloc (ifaces.count * sizeof (jshort));
1174
1175 _Jv_GenerateITable (klass, &ifaces, itable_offsets);
1176
1177 jshort cls_iindex =
1178 _Jv_FindIIndex (ifaces.list, itable_offsets, ifaces.count);
1179
1180 for (int i=0; i < ifaces.count; i++)
1181 {
1182 ifaces.list[i]->idt->iface.ioffsets[cls_iindex] =
1183 itable_offsets[i];
1184 }
1185
1186 klass->idt->cls.iindex = cls_iindex;
1187
1188 _Jv_Free (ifaces.list);
1189 _Jv_Free (itable_offsets);
1190 }
1191 else
1192 {
1193 klass->idt->cls.iindex = SHRT_MAX;
1194 }
1195}
1196
1197// Return index of item in list, or -1 if item is not present.
1198inline jshort
1199_Jv_IndexOf (void *item, void **list, jshort list_len)
1200{
1201 for (int i=0; i < list_len; i++)
1202 {
1203 if (list[i] == item)
1204 return i;
1205 }
1206 return -1;
1207}
1208
1209// Find all unique interfaces directly or indirectly implemented by klass.
1210// Returns the size of the interface dispatch table (itable) for klass, which
1211// is the number of unique interfaces plus the total number of methods that
1212// those interfaces declare. May extend ifaces if required.
1213jshort
1214_Jv_GetInterfaces (jclass klass, _Jv_ifaces *ifaces)
1215{
1216 jshort result = 0;
1217
1218 for (int i=0; i < klass->interface_count; i++)
1219 {
1220 jclass iface = klass->interfaces[i];
1221 if (_Jv_IndexOf (iface, (void **) ifaces->list, ifaces->count) == -1)
1222 {
1223 if (ifaces->count + 1 >= ifaces->len)
1224 {
1225 /* Resize ifaces list */
1226 ifaces->len = ifaces->len * 2;
1227 ifaces->list = (jclass *) _Jv_Realloc (ifaces->list,
1228 ifaces->len * sizeof(jclass));
1229 }
1230 ifaces->list[ifaces->count] = iface;
1231 ifaces->count++;
1232
1233 result += _Jv_GetInterfaces (klass->interfaces[i], ifaces);
1234 }
1235 }
1236
1237 if (klass->isInterface())
1238 {
1239 result += klass->method_count + 1;
1240 }
1241 else
1242 {
1243 if (klass->superclass)
1244 {
1245 result += _Jv_GetInterfaces (klass->superclass, ifaces);
1246 }
1247 }
1248 return result;
1249}
1250
1251// Fill out itable in klass, resolving method declarations in each ifaces.
1252// itable_offsets is filled out with the position of each iface in itable,
1253// such that itable[itable_offsets[n]] == ifaces.list[n].
1254void
1255_Jv_GenerateITable (jclass klass, _Jv_ifaces *ifaces, jshort *itable_offsets)
1256{
1257 void **itable = klass->idt->cls.itable;
1258 jshort itable_pos = 0;
1259
1260 for (int i=0; i < ifaces->count; i++)
1261 {
1262 jclass iface = ifaces->list[i];
1263 itable_offsets[i] = itable_pos;
1264 itable_pos = _Jv_AppendPartialITable (klass, iface, itable, itable_pos);
1265
1266 /* Create interface dispatch table for iface */
1267 if (iface->idt == NULL)
1268 {
1269 iface->idt =
1270 (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
1271
1272 // The first element of ioffsets is its length (itself included).
1273 jshort *ioffsets =
1274 (jshort *) _Jv_Malloc (INITIAL_IOFFSETS_LEN * sizeof (jshort));
1275 ioffsets[0] = INITIAL_IOFFSETS_LEN;
1276 for (int i=1; i < INITIAL_IOFFSETS_LEN; i++)
1277 ioffsets[i] = -1;
1278
1279 iface->idt->iface.ioffsets = ioffsets;
1280 }
1281 }
1282}
1283
1284// Format method name for use in error messages.
1285jstring
1286_Jv_GetMethodString (jclass klass, _Jv_Utf8Const *name)
1287{
1288 jstring r = JvNewStringUTF (klass->name->data);
1289 r = r->concat (JvNewStringUTF ("."));
1290 r = r->concat (JvNewStringUTF (name->data));
1291 return r;
1292}
1293
1294void
1295_Jv_ThrowNoSuchMethodError ()
1296{
1297 throw new java::lang::NoSuchMethodError;
1298}
1299
1300// Each superinterface of a class (i.e. each interface that the class
1301// directly or indirectly implements) has a corresponding "Partial
1302// Interface Dispatch Table" whose size is (number of methods + 1) words.
1303// The first word is a pointer to the interface (i.e. the java.lang.Class
1304// instance for that interface). The remaining words are pointers to the
1305// actual methods that implement the methods declared in the interface,
1306// in order of declaration.
1307//
1308// Append partial interface dispatch table for "iface" to "itable", at
1309// position itable_pos.
1310// Returns the offset at which the next partial ITable should be appended.
1311jshort
1312_Jv_AppendPartialITable (jclass klass, jclass iface, void **itable,
1313 jshort pos)
1314{
1315 using namespace java::lang::reflect;
1316
1317 itable[pos++] = (void *) iface;
1318 _Jv_Method *meth;
1319
1320 for (int j=0; j < iface->method_count; j++)
1321 {
1322 meth = NULL;
1323 for (jclass cl = klass; cl; cl = cl->getSuperclass())
1324 {
1325 meth = _Jv_GetMethodLocal (cl, iface->methods[j].name,
1326 iface->methods[j].signature);
1327
1328 if (meth)
1329 break;
1330 }
1331
1332 if (meth && (meth->name->data[0] == '<'))
1333 {
1334 // leave a placeholder in the itable for hidden init methods.
1335 itable[pos] = NULL;
1336 }
1337 else if (meth)
1338 {
1339 if (Modifier::isStatic(meth->accflags))
1340 throw new java::lang::IncompatibleClassChangeError
1341 (_Jv_GetMethodString (klass, meth->name));
1342 if (Modifier::isAbstract(meth->accflags))
1343 throw new java::lang::AbstractMethodError
1344 (_Jv_GetMethodString (klass, meth->name));
1345 if (! Modifier::isPublic(meth->accflags))
1346 throw new java::lang::IllegalAccessError
1347 (_Jv_GetMethodString (klass, meth->name));
1348
1349 itable[pos] = meth->ncode;
1350 }
1351 else
1352 {
1353 // The method doesn't exist in klass. Binary compatibility rules
1354 // permit this, so we delay the error until runtime using a pointer
1355 // to a method which throws an exception.
1356 itable[pos] = (void *) _Jv_ThrowNoSuchMethodError;
1357 }
1358 pos++;
1359 }
1360
1361 return pos;
1362}
1363
1364static _Jv_Mutex_t iindex_mutex;
1365static bool iindex_mutex_initialized = false;
1366
1367// We need to find the correct offset in the Class Interface Dispatch
1368// Table for a given interface. Once we have that, invoking an interface
1369// method just requires combining the Method's index in the interface
1370// (known at compile time) to get the correct method. Doing a type test
1371// (cast or instanceof) is the same problem: Once we have a possible Partial
1372// Interface Dispatch Table, we just compare the first element to see if it
1373// matches the desired interface. So how can we find the correct offset?
1374// Our solution is to keep a vector of candiate offsets in each interface
1375// (idt->iface.ioffsets), and in each class we have an index
1376// (idt->cls.iindex) used to select the correct offset from ioffsets.
1377//
1378// Calculate and return iindex for a new class.
1379// ifaces is a vector of num interfaces that the class implements.
1380// offsets[j] is the offset in the interface dispatch table for the
1381// interface corresponding to ifaces[j].
1382// May extend the interface ioffsets if required.
1383jshort
1384_Jv_FindIIndex (jclass *ifaces, jshort *offsets, jshort num)
1385{
1386 int i;
1387 int j;
1388
1389 // Acquire a global lock to prevent itable corruption in case of multiple
1390 // classes that implement an intersecting set of interfaces being linked
1391 // simultaneously. We can assume that the mutex will be initialized
1392 // single-threaded.
1393 if (! iindex_mutex_initialized)
1394 {
1395 _Jv_MutexInit (&iindex_mutex);
1396 iindex_mutex_initialized = true;
1397 }
1398
1399 _Jv_MutexLock (&iindex_mutex);
1400
1401 for (i=1;; i++) /* each potential position in ioffsets */
1402 {
1403 for (j=0;; j++) /* each iface */
1404 {
1405 if (j >= num)
1406 goto found;
1407 if (i >= ifaces[j]->idt->iface.ioffsets[0])
1408 continue;
1409 int ioffset = ifaces[j]->idt->iface.ioffsets[i];
1410 /* We can potentially share this position with another class. */
1411 if (ioffset >= 0 && ioffset != offsets[j])
1412 break; /* Nope. Try next i. */
1413 }
1414 }
1415 found:
1416 for (j = 0; j < num; j++)
1417 {
1418 int len = ifaces[j]->idt->iface.ioffsets[0];
1419 if (i >= len)
1420 {
1421 /* Resize ioffsets. */
1422 int newlen = 2 * len;
1423 if (i >= newlen)
1424 newlen = i + 3;
1425 jshort *old_ioffsets = ifaces[j]->idt->iface.ioffsets;
1426 jshort *new_ioffsets = (jshort *) _Jv_Realloc (old_ioffsets,
1427 newlen * sizeof(jshort));
1428 new_ioffsets[0] = newlen;
1429
1430 while (len < newlen)
1431 new_ioffsets[len++] = -1;
1432
1433 ifaces[j]->idt->iface.ioffsets = new_ioffsets;
1434 }
1435 ifaces[j]->idt->iface.ioffsets[i] = offsets[j];
1436 }
1437
1438 _Jv_MutexUnlock (&iindex_mutex);
1439
1440 return i;
1441}
1442
1443// Only used by serialization
1444java::lang::reflect::Field *
1445java::lang::Class::getPrivateField (jstring name)
1446{
1447 int hash = name->hashCode ();
1448
1449 java::lang::reflect::Field* rfield;
1450 for (int i = 0; i < field_count; i++)
1451 {
1452 _Jv_Field *field = &fields[i];
1453 if (! _Jv_equal (field->name, name, hash))
1454 continue;
1455 rfield = new java::lang::reflect::Field ();
1456 rfield->offset = (char*) field - (char*) fields;
1457 rfield->declaringClass = this;
1458 rfield->name = name;
1459 return rfield;
1460 }
1461 jclass superclass = getSuperclass();
1462 if (superclass == NULL)
1463 return NULL;
1464 rfield = superclass->getPrivateField(name);
1465 for (int i = 0; i < interface_count && rfield == NULL; ++i)
1466 rfield = interfaces[i]->getPrivateField (name);
1467 return rfield;
1468}
1469
1470// Only used by serialization
1471java::lang::reflect::Method *
1472java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *param_types)
1473{
1474 jstring partial_sig = getSignature (param_types, false);
1475 jint p_len = partial_sig->length();
1476 _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
1477 for (Class *klass = this; klass; klass = klass->getSuperclass())
1478 {
1479 int i = klass->isPrimitive () ? 0 : klass->method_count;
1480 while (--i >= 0)
1481 {
1482 if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
1483 && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len))
1484 {
1485 // Found it.
1486 using namespace java::lang::reflect;
1487
1488 Method *rmethod = new Method ();
1489 rmethod->offset = ((char *) (&klass->methods[i])
1490 - (char *) klass->methods);
1491 rmethod->declaringClass = klass;
1492 return rmethod;
1493 }
1494 }
1495 }
1496 throw new java::lang::NoSuchMethodException;
1497}
1498
1499// Private accessor method for Java code to retrieve the protection domain.
1500java::security::ProtectionDomain *
1501java::lang::Class::getProtectionDomain0 ()
1502{
1503 return protectionDomain;
1504}
1505
1506// Functions for indirect dispatch (symbolic virtual method binding) support.
1507
1508// Resolve entries in the virtual method offset symbol table
1509// (klass->otable_syms). The vtable offset (in bytes) for each resolved method
1510// is placed at the corresponding position in the virtual method offset table
1511// (klass->otable). A single otable and otable_syms pair may be shared by many
1512// classes.
1513void
1514_Jv_LinkOffsetTable(jclass klass)
1515{
1516 //// FIXME: Need to lock the otable ////
1517
1518 if (klass->otable == NULL
1519 || klass->otable->state != 0)
1520 return;
1521
1522 klass->otable->state = 1;
1523
1524 int index = 0;
1525 _Jv_MethodSymbol sym = klass->otable_syms[0];
1526
1527 while (sym.name != NULL)
1528 {
1529 jclass target_class = _Jv_FindClass (sym.class_name, NULL);
1530 _Jv_Method *meth = NULL;
1531
1532 if (target_class != NULL)
1533 if (target_class->isInterface())
1534 {
1535 // FIXME: This does not yet fully conform to binary compatibility
1536 // rules. It will break if a declaration is moved into a
1537 // superinterface.
1538 for (int i=0; i < target_class->method_count; i++)
1539 {
1540 meth = &target_class->methods[i];
1541 if (_Jv_equalUtf8Consts (sym.name, meth->name)
1542 && _Jv_equalUtf8Consts (sym.signature, meth->signature))
1543 {
1544 klass->otable->offsets[index] = i + 1;
1545 break;
1546 }
1547 }
1548 }
1549 else
1550 {
1551 // If the target class does not have a vtable_method_count yet,
1552 // then we can't tell the offsets for its methods, so we must lay
1553 // it out now.
1554 if (target_class->vtable_method_count == -1)
1555 {
1556 JvSynchronize sync (target_class);
1557 _Jv_LayoutVTableMethods (target_class);
1558 }
1559
1560 meth = _Jv_LookupDeclaredMethod(target_class, sym.name,
1561 sym.signature);
1562
1563 if (meth != NULL)
1564 {
1565 klass->otable->offsets[index] =
1566 _Jv_VTable::idx_to_offset (meth->index);
1567 }
1568 }
1569
1570 if (meth == NULL)
1571 // FIXME: This should be special index for ThrowNoSuchMethod().
1572 klass->otable->offsets[index] = -1;
1573
1574 sym = klass->otable_syms[++index];
1575 }
1576}
1577
1578// Returns true if METH should get an entry in a VTable.
1579static jboolean
1580isVirtualMethod (_Jv_Method *meth)
1581{
1582 using namespace java::lang::reflect;
1583 return (((meth->accflags & (Modifier::STATIC | Modifier::PRIVATE)) == 0)
1584 && meth->name->data[0] != '<');
1585}
1586
1587// This is put in empty vtable slots.
1588static void
1589_Jv_abstractMethodError (void)
1590{
1591 throw new java::lang::AbstractMethodError();
1592}
1593
1594// Prepare virtual method declarations in KLASS, and any superclasses as
1595// required, by determining their vtable index, setting method->index, and
1596// finally setting the class's vtable_method_count. Must be called with the
1597// lock for KLASS held.
1598void
1599_Jv_LayoutVTableMethods (jclass klass)
1600{
1601 if (klass->vtable != NULL || klass->isInterface()
1602 || klass->vtable_method_count != -1)
1603 return;
1604
1605 jclass superclass = klass->superclass;
1606
1607 if (superclass != NULL && superclass->vtable_method_count == -1)
1608 {
1609 JvSynchronize sync (superclass);
1610 _Jv_LayoutVTableMethods (superclass);
1611 }
1612
1613 int index = (superclass == NULL ? 0 : superclass->vtable_method_count);
1614
1615 for (int i = 0; i < klass->method_count; ++i)
1616 {
1617 _Jv_Method *meth = &klass->methods[i];
1618 _Jv_Method *super_meth = NULL;
1619
1620 if (! isVirtualMethod (meth))
1621 continue;
1622
1623 if (superclass != NULL)
1624 {
1625 super_meth = _Jv_LookupDeclaredMethod (superclass, meth->name,
1626 meth->signature);
1627 }
1628
1629 if (super_meth)
1630 meth->index = super_meth->index;
1631 else if (! (meth->accflags & java::lang::reflect::Modifier::FINAL)
1632 && ! (klass->accflags & java::lang::reflect::Modifier::FINAL))
1633 meth->index = index++;
1634 }
1635
1636 klass->vtable_method_count = index;
1637}
1638
1639// Set entries in VTABLE for virtual methods declared in KLASS. If
1640// KLASS has an immediate abstract parent, recursively do its methods
1641// first. FLAGS is used to determine which slots we've actually set.
1642void
1643_Jv_SetVTableEntries (jclass klass, _Jv_VTable *vtable, jboolean *flags)
1644{
1645 using namespace java::lang::reflect;
1646
1647 jclass superclass = klass->getSuperclass();
1648
1649 if (superclass != NULL && (superclass->getModifiers() & Modifier::ABSTRACT))
1650 _Jv_SetVTableEntries (superclass, vtable, flags);
1651
1652 for (int i = klass->method_count - 1; i >= 0; i--)
1653 {
1654 _Jv_Method *meth = &klass->methods[i];
1655 if (meth->index == (_Jv_ushort) -1)
1656 continue;
1657 if ((meth->accflags & Modifier::ABSTRACT))
1658 {
1659 vtable->set_method(meth->index, (void *) &_Jv_abstractMethodError);
1660 flags[meth->index] = false;
1661 }
1662 else
1663 {
1664 vtable->set_method(meth->index, meth->ncode);
1665 flags[meth->index] = true;
1666 }
1667 }
1668}
1669
1670// Allocate and lay out the virtual method table for KLASS. This will also
1671// cause vtables to be generated for any non-abstract superclasses, and
1672// virtual method layout to occur for any abstract superclasses. Must be
1673// called with monitor lock for KLASS held.
1674void
1675_Jv_MakeVTable (jclass klass)
1676{
1677 using namespace java::lang::reflect;
1678
1679 if (klass->vtable != NULL || klass->isInterface()
1680 || (klass->accflags & Modifier::ABSTRACT))
1681 return;
1682
1683 // out before we can create a vtable.
1684 if (klass->vtable_method_count == -1)
1685 _Jv_LayoutVTableMethods (klass);
1686
1687 // Allocate the new vtable.
1688 _Jv_VTable *vtable = _Jv_VTable::new_vtable (klass->vtable_method_count);
1689 klass->vtable = vtable;
1690
1691 jboolean flags[klass->vtable_method_count];
1692 for (int i = 0; i < klass->vtable_method_count; ++i)
1693 flags[i] = false;
1694
1695 // Copy the vtable of the closest non-abstract superclass.
1696 jclass superclass = klass->superclass;
1697 if (superclass != NULL)
1698 {
1699 while ((superclass->accflags & Modifier::ABSTRACT) != 0)
1700 superclass = superclass->superclass;
1701
1702 if (superclass->vtable == NULL)
1703 {
1704 JvSynchronize sync (superclass);
1705 _Jv_MakeVTable (superclass);
1706 }
1707
1708 for (int i = 0; i < superclass->vtable_method_count; ++i)
1709 {
1710 vtable->set_method (i, superclass->vtable->get_method (i));
1711 flags[i] = true;
1712 }
1713 }
1714
1715 // Set the class pointer and GC descriptor.
1716 vtable->clas = klass;
1717 vtable->gc_descr = _Jv_BuildGCDescr (klass);
1718
1719 // For each virtual declared in klass and any immediate abstract
1720 // superclasses, set new vtable entry or override an old one.
1721 _Jv_SetVTableEntries (klass, vtable, flags);
1722
1723 // It is an error to have an abstract method in a concrete class.
1724 if (! (klass->accflags & Modifier::ABSTRACT))
1725 {
1726 for (int i = 0; i < klass->vtable_method_count; ++i)
1727 if (! flags[i])
1728 // FIXME: messsage.
1729 throw new java::lang::AbstractMethodError ();
1730 }
1731}
Note: See TracBrowser for help on using the repository browser.