1 // natClass.cc - Implementation of java.lang.Class native methods.
3 /* Copyright (C) 1998, 1999, 2000 Cygnus Solutions
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
16 #pragma implementation "Class.h"
20 #include <java/lang/Class.h>
21 #include <java/lang/ClassLoader.h>
22 #include <java/lang/String.h>
23 #include <java/lang/reflect/Modifier.h>
24 #include <java/lang/reflect/Member.h>
25 #include <java/lang/reflect/Method.h>
26 #include <java/lang/reflect/Field.h>
27 #include <java/lang/reflect/Constructor.h>
28 #include <java/lang/AbstractMethodError.h>
29 #include <java/lang/ClassNotFoundException.h>
30 #include <java/lang/IllegalAccessException.h>
31 #include <java/lang/IllegalAccessError.h>
32 #include <java/lang/IncompatibleClassChangeError.h>
33 #include <java/lang/InstantiationException.h>
34 #include <java/lang/NoClassDefFoundError.h>
35 #include <java/lang/NoSuchFieldException.h>
36 #include <java/lang/NoSuchMethodException.h>
37 #include <java/lang/Thread.h>
38 #include <java/lang/NullPointerException.h>
39 #include <java/lang/System.h>
40 #include <java/lang/SecurityManager.h>
41 #include <java/lang/StringBuffer.h>
43 #include <java-cpool.h>
47 #define CloneableClass _CL_Q34java4lang9Cloneable
48 extern java::lang::Class CloneableClass
;
49 #define ObjectClass _CL_Q34java4lang6Object
50 extern java::lang::Class ObjectClass
;
51 #define ErrorClass _CL_Q34java4lang5Error
52 extern java::lang::Class ErrorClass
;
53 #define ClassClass _CL_Q34java4lang5Class
54 extern java::lang::Class ClassClass
;
55 #define MethodClass _CL_Q44java4lang7reflect6Method
56 extern java::lang::Class MethodClass
;
57 #define FieldClass _CL_Q44java4lang7reflect5Field
58 extern java::lang::Class FieldClass
;
59 #define ConstructorClass _CL_Q44java4lang7reflect11Constructor
60 extern java::lang::Class ConstructorClass
;
62 // Some constants we use to look up the class initializer.
63 static _Jv_Utf8Const
*void_signature
= _Jv_makeUtf8Const ("()V", 3);
64 static _Jv_Utf8Const
*clinit_name
= _Jv_makeUtf8Const ("<clinit>", 8);
65 static _Jv_Utf8Const
*init_name
= _Jv_makeUtf8Const ("<init>", 6);
70 java::lang::Class::forName (jstring className
)
73 JvThrow (new java::lang::NullPointerException
);
76 // FIXME: should check syntax of CLASSNAME and throw
77 // IllegalArgumentException on failure.
79 // FIXME: should use class loader from calling method.
80 jclass klass
= _Jv_FindClass (className
, NULL
);
82 jsize length
= _Jv_GetStringUTFLength (className
);
84 _Jv_GetStringUTFRegion (className
, 0, length
, buffer
);
86 // FIXME: should check syntax of CLASSNAME and throw
87 // IllegalArgumentException on failure.
88 _Jv_Utf8Const
*name
= _Jv_makeUtf8Const (buffer
, length
);
90 // FIXME: should use class loader from calling method.
91 jclass klass
= (buffer
[0] == '['
92 ? _Jv_FindClassFromSignature (name
->data
, NULL
)
93 : _Jv_FindClass (name
, NULL
));
96 JvThrow (new java::lang::ClassNotFoundException (className
));
101 java::lang::reflect::Constructor
*
102 java::lang::Class::getConstructor (JArray
<jclass
> *param_types
)
104 jstring partial_sig
= getSignature (param_types
, true);
105 jint hash
= partial_sig
->hashCode ();
107 int i
= isPrimitive () ? 0 : method_count
;
110 // FIXME: access checks.
111 if (_Jv_equalUtf8Consts (methods
[i
].name
, init_name
)
112 && _Jv_equal (methods
[i
].signature
, partial_sig
, hash
))
114 // Found it. For getConstructor, the constructor must be
116 using namespace java::lang::reflect
;
117 if (! Modifier::isPublic(methods
[i
].accflags
))
119 Constructor
*cons
= new Constructor ();
120 cons
->offset
= (char *) (&methods
[i
]) - (char *) methods
;
121 cons
->declaringClass
= this;
125 JvThrow (new java::lang::NoSuchMethodException
);
128 JArray
<java::lang::reflect::Constructor
*> *
129 java::lang::Class::_getConstructors (jboolean declared
)
131 // FIXME: this method needs access checks.
133 int numConstructors
= 0;
134 int max
= isPrimitive () ? 0 : method_count
;
136 for (i
= max
; --i
>= 0; )
138 _Jv_Method
*method
= &methods
[i
];
139 if (method
->name
== NULL
140 && ! _Jv_equalUtf8Consts (method
->name
, init_name
))
143 && ! java::lang::reflect::Modifier::isPublic(method
->accflags
))
147 JArray
<java::lang::reflect::Constructor
*> *result
148 = (JArray
<java::lang::reflect::Constructor
*> *)
149 JvNewObjectArray (numConstructors
, &ConstructorClass
, NULL
);
150 java::lang::reflect::Constructor
** cptr
= elements (result
);
151 for (i
= 0; i
< max
; i
++)
153 _Jv_Method
*method
= &methods
[i
];
154 if (method
->name
== NULL
155 && ! _Jv_equalUtf8Consts (method
->name
, init_name
))
158 && ! java::lang::reflect::Modifier::isPublic(method
->accflags
))
160 java::lang::reflect::Constructor
*cons
161 = new java::lang::reflect::Constructor ();
162 cons
->offset
= (char *) method
- (char *) methods
;
163 cons
->declaringClass
= this;
169 java::lang::reflect::Constructor
*
170 java::lang::Class::getDeclaredConstructor (JArray
<jclass
> *param_types
)
172 jstring partial_sig
= getSignature (param_types
, true);
173 jint hash
= partial_sig
->hashCode ();
175 int i
= isPrimitive () ? 0 : method_count
;
178 // FIXME: access checks.
179 if (_Jv_equalUtf8Consts (methods
[i
].name
, init_name
)
180 && _Jv_equal (methods
[i
].signature
, partial_sig
, hash
))
183 using namespace java::lang::reflect
;
184 Constructor
*cons
= new Constructor ();
185 cons
->offset
= (char *) (&methods
[i
]) - (char *) methods
;
186 cons
->declaringClass
= this;
190 JvThrow (new java::lang::NoSuchMethodException
);
193 java::lang::reflect::Field
*
194 java::lang::Class::getField (jstring name
, jint hash
)
196 java::lang::reflect::Field
* rfield
;
197 for (int i
= 0; i
< field_count
; i
++)
199 _Jv_Field
*field
= &fields
[i
];
200 if (! _Jv_equal (field
->name
, name
, hash
))
202 if (! (field
->getModifiers() & java::lang::reflect::Modifier::PUBLIC
))
204 rfield
= new java::lang::reflect::Field ();
205 rfield
->offset
= (char*) field
- (char*) fields
;
206 rfield
->declaringClass
= this;
210 jclass superclass
= getSuperclass();
211 if (superclass
== NULL
)
213 rfield
= superclass
->getField(name
, hash
);
214 for (int i
= 0; i
< interface_count
&& rfield
== NULL
; ++i
)
215 rfield
= interfaces
[i
]->getField (name
, hash
);
219 java::lang::reflect::Field
*
220 java::lang::Class::getDeclaredField (jstring name
)
222 java::lang::SecurityManager
*s
= java::lang::System::getSecurityManager();
224 s
->checkMemberAccess (this, java::lang::reflect::Member::DECLARED
);
225 int hash
= name
->hashCode();
226 for (int i
= 0; i
< field_count
; i
++)
228 _Jv_Field
*field
= &fields
[i
];
229 if (! _Jv_equal (field
->name
, name
, hash
))
231 java::lang::reflect::Field
* rfield
= new java::lang::reflect::Field ();
232 rfield
->offset
= (char*) field
- (char*) fields
;
233 rfield
->declaringClass
= this;
237 JvThrow (new java::lang::NoSuchFieldException (name
));
240 JArray
<java::lang::reflect::Field
*> *
241 java::lang::Class::getDeclaredFields (void)
243 java::lang::SecurityManager
*s
= java::lang::System::getSecurityManager();
245 s
->checkMemberAccess (this, java::lang::reflect::Member::DECLARED
);
246 JArray
<java::lang::reflect::Field
*> *result
247 = (JArray
<java::lang::reflect::Field
*> *)
248 JvNewObjectArray (field_count
, &FieldClass
, NULL
);
249 java::lang::reflect::Field
** fptr
= elements (result
);
250 for (int i
= 0; i
< field_count
; i
++)
252 _Jv_Field
*field
= &fields
[i
];
253 java::lang::reflect::Field
* rfield
= new java::lang::reflect::Field ();
254 rfield
->offset
= (char*) field
- (char*) fields
;
255 rfield
->declaringClass
= this;
262 java::lang::Class::getSignature (java::lang::StringBuffer
*buffer
)
265 buffer
->append((jchar
) method_count
);
268 jstring name
= getName();
269 if (name
->charAt(0) != '[')
270 buffer
->append((jchar
) 'L');
271 buffer
->append(name
);
272 if (name
->charAt(0) != '[')
273 buffer
->append((jchar
) ';');
277 // This doesn't have to be native. It is an implementation detail
278 // only called from the C++ code, though, so maybe this is clearer.
280 java::lang::Class::getSignature (JArray
<jclass
> *param_types
,
281 jboolean is_constructor
)
283 java::lang::StringBuffer
*buf
= new java::lang::StringBuffer ();
284 buf
->append((jchar
) '(');
285 jclass
*v
= elements (param_types
);
286 for (int i
= 0; i
< param_types
->length
; ++i
)
287 v
[i
]->getSignature(buf
);
288 buf
->append((jchar
) ')');
290 buf
->append((jchar
) 'V');
291 return buf
->toString();
294 java::lang::reflect::Method
*
295 java::lang::Class::getDeclaredMethod (jstring name
,
296 JArray
<jclass
> *param_types
)
298 jstring partial_sig
= getSignature (param_types
, false);
299 jint p_len
= partial_sig
->length();
300 _Jv_Utf8Const
*utf_name
= _Jv_makeUtf8Const (name
);
301 int i
= isPrimitive () ? 0 : method_count
;
304 // FIXME: access checks.
305 if (_Jv_equalUtf8Consts (methods
[i
].name
, utf_name
)
306 && _Jv_equaln (methods
[i
].signature
, partial_sig
, p_len
))
309 using namespace java::lang::reflect
;
310 Method
*rmethod
= new Method ();
311 rmethod
->offset
= (char*) (&methods
[i
]) - (char*) methods
;
312 rmethod
->declaringClass
= this;
315 JvThrow (new java::lang::NoSuchMethodException
);
318 JArray
<java::lang::reflect::Method
*> *
319 java::lang::Class::getDeclaredMethods (void)
322 int max
= isPrimitive () ? 0 : method_count
;
324 for (i
= max
; --i
>= 0; )
326 _Jv_Method
*method
= &methods
[i
];
327 if (method
->name
== NULL
328 || _Jv_equalUtf8Consts (method
->name
, clinit_name
)
329 || _Jv_equalUtf8Consts (method
->name
, init_name
))
333 JArray
<java::lang::reflect::Method
*> *result
334 = (JArray
<java::lang::reflect::Method
*> *)
335 JvNewObjectArray (numMethods
, &MethodClass
, NULL
);
336 java::lang::reflect::Method
** mptr
= elements (result
);
337 for (i
= 0; i
< max
; i
++)
339 _Jv_Method
*method
= &methods
[i
];
340 if (method
->name
== NULL
341 || _Jv_equalUtf8Consts (method
->name
, clinit_name
)
342 || _Jv_equalUtf8Consts (method
->name
, init_name
))
344 java::lang::reflect::Method
* rmethod
345 = new java::lang::reflect::Method ();
346 rmethod
->offset
= (char*) method
- (char*) methods
;
347 rmethod
->declaringClass
= this;
354 java::lang::Class::getName (void)
356 char buffer
[name
->length
+ 1];
357 memcpy (buffer
, name
->data
, name
->length
);
358 buffer
[name
->length
] = '\0';
359 return _Jv_NewStringUTF (buffer
);
363 java::lang::Class::getClasses (void)
370 java::lang::Class::getDeclaredClasses (void)
372 checkMemberAccess (java::lang::reflect::Member::DECLARED
);
373 JvFail ("java::lang::Class::getDeclaredClasses not implemented");
374 return NULL
; // Placate compiler.
377 // This is marked as unimplemented in the JCL book.
379 java::lang::Class::getDeclaringClass (void)
381 JvFail ("java::lang::Class::getDeclaringClass unimplemented");
382 return NULL
; // Placate compiler.
386 java::lang::Class::_getFields (JArray
<java::lang::reflect::Field
*> *result
,
390 for (int i
= 0; i
< field_count
; i
++)
392 _Jv_Field
*field
= &fields
[i
];
393 if (! (field
->getModifiers() & java::lang::reflect::Modifier::PUBLIC
))
399 java::lang::reflect::Field
*rfield
400 = new java::lang::reflect::Field ();
401 rfield
->offset
= (char *) field
- (char *) fields
;
402 rfield
->declaringClass
= this;
403 rfield
->name
= _Jv_NewStringUtf8Const (field
->name
);
404 (elements (result
))[offset
+ i
] = rfield
;
407 jclass superclass
= getSuperclass();
408 if (superclass
!= NULL
)
410 int s_count
= superclass
->_getFields (result
, offset
);
414 for (int i
= 0; i
< interface_count
; ++i
)
416 int f_count
= interfaces
[i
]->_getFields (result
, offset
);
423 JArray
<java::lang::reflect::Field
*> *
424 java::lang::Class::getFields (void)
426 using namespace java::lang::reflect
;
428 int count
= _getFields (NULL
, 0);
430 JArray
<java::lang::reflect::Field
*> *result
431 = ((JArray
<java::lang::reflect::Field
*> *)
432 JvNewObjectArray (count
, &FieldClass
, NULL
));
434 _getFields (result
, 0);
440 java::lang::Class::getInterfaces (void)
442 jobjectArray r
= JvNewObjectArray (interface_count
, getClass (), NULL
);
443 jobject
*data
= elements (r
);
444 for (int i
= 0; i
< interface_count
; ++i
)
445 data
[i
] = interfaces
[i
];
446 return reinterpret_cast<JArray
<jclass
> *> (r
);
449 java::lang::reflect::Method
*
450 java::lang::Class::getMethod (jstring name
, JArray
<jclass
> *param_types
)
452 jstring partial_sig
= getSignature (param_types
, false);
453 jint p_len
= partial_sig
->length();
454 _Jv_Utf8Const
*utf_name
= _Jv_makeUtf8Const (name
);
455 for (Class
*klass
= this; klass
; klass
= klass
->getSuperclass())
457 int i
= klass
->isPrimitive () ? 0 : klass
->method_count
;
460 // FIXME: access checks.
461 if (_Jv_equalUtf8Consts (klass
->methods
[i
].name
, utf_name
)
462 && _Jv_equaln (klass
->methods
[i
].signature
, partial_sig
, p_len
))
465 using namespace java::lang::reflect
;
466 Method
*rmethod
= new Method ();
467 rmethod
->offset
= (char*) (&klass
->methods
[i
]) - (char*) methods
;
468 rmethod
->declaringClass
= klass
;
473 JvThrow (new java::lang::NoSuchMethodException
);
476 JArray
<java::lang::reflect::Method
*> *
477 java::lang::Class::getMethods (void)
479 JvFail ("java::lang::Class::getMethods not implemented");
483 java::lang::Class::isAssignableFrom (jclass klass
)
487 // Primitive types must be equal, which we just tested for.
488 if (isPrimitive () || ! klass
|| klass
->isPrimitive())
491 // If target is array, so must source be.
494 if (! klass
->isArray())
496 return getComponentType()->isAssignableFrom(klass
->getComponentType());
499 if (isAssignableFrom (klass
->getSuperclass()))
504 // See if source implements this interface.
505 for (int i
= 0; i
< klass
->interface_count
; ++i
)
507 jclass interface
= klass
->interfaces
[i
];
508 // FIXME: ensure that class is prepared here.
510 if (isAssignableFrom (interface
))
519 java::lang::Class::isInstance (jobject obj
)
521 if (! obj
|| isPrimitive ())
523 return isAssignableFrom (obj
->getClass());
527 java::lang::Class::isInterface (void)
529 return (accflags
& java::lang::reflect::Modifier::INTERFACE
) != 0;
533 java::lang::Class::newInstance (void)
535 // FIXME: do accessibility checks here. There currently doesn't
536 // seem to be any way to do these.
537 // FIXME: we special-case one check here just to pass a Plum Hall
538 // test. Once access checking is implemented, remove this.
539 if (this == &ClassClass
)
540 JvThrow (new java::lang::IllegalAccessException
);
545 || java::lang::reflect::Modifier::isAbstract(accflags
))
546 JvThrow (new java::lang::InstantiationException
);
548 _Jv_InitClass (this);
550 _Jv_Method
*meth
= _Jv_GetMethodLocal (this, init_name
, void_signature
);
552 JvThrow (new java::lang::NoSuchMethodException
);
554 jobject r
= JvAllocObject (this);
555 ((void (*) (jobject
)) meth
->ncode
) (r
);
560 java::lang::Class::finalize (void)
563 JvAssert (_Jv_IsInterpretedClass (this));
564 _Jv_UnregisterClass (this);
570 java::lang::Class::hackRunInitializers (void)
572 _Jv_Method
*meth
= _Jv_GetMethodLocal (this, clinit_name
, void_signature
);
574 ((void (*) (void)) meth
->ncode
) ();
577 // This implements the initialization process for a class. From Spec
580 java::lang::Class::initializeClass (void)
582 // Short-circuit to avoid needless locking.
583 if (state
== JV_STATE_DONE
)
586 // do this before we enter the monitor below, since this can cause
587 // exceptions. Here we assume, that reading "state" is an atomic
588 // operation, I pressume that is true? --Kresten
589 if (state
< JV_STATE_LINKED
)
592 if (_Jv_IsInterpretedClass (this))
594 java::lang::ClassLoader::resolveClass0 (this);
597 _Jv_MonitorEnter (this);
603 _Jv_MonitorEnter (this);
604 _Jv_PrepareCompiledClass (this);
610 _Jv_MonitorEnter (this);
614 java::lang::Thread
*self
= java::lang::Thread::currentThread();
615 // FIXME: `self' can be null at startup. Hence this nasty trick.
616 self
= (java::lang::Thread
*) ((long) self
| 1);
617 while (state
== JV_STATE_IN_PROGRESS
&& thread
&& thread
!= self
)
621 if (state
== JV_STATE_DONE
|| state
== JV_STATE_IN_PROGRESS
|| thread
== self
)
623 _Jv_MonitorExit (this);
628 if (state
== JV_STATE_ERROR
)
630 _Jv_MonitorExit (this);
631 JvThrow (new java::lang::NoClassDefFoundError
);
636 state
= JV_STATE_IN_PROGRESS
;
637 _Jv_MonitorExit (this);
640 if (! isInterface () && superclass
)
642 // FIXME: We can't currently catch a Java exception in C++ code.
643 // So instead we call a Java trampoline. It returns an
644 // exception, or null.
645 jobject except
= superclass
->hackTrampoline(0, NULL
);
648 // Caught an exception.
649 _Jv_MonitorEnter (this);
650 state
= JV_STATE_ERROR
;
652 _Jv_MonitorExit (this);
658 // FIXME: once again we have to go through a trampoline.
659 java::lang::Throwable
*except
= hackTrampoline (1, NULL
);
664 _Jv_MonitorEnter (this);
665 state
= JV_STATE_DONE
;
669 if (! ErrorClass
.isInstance(except
))
671 // Once again we must use the trampoline. In this case we
672 // have to detect an OutOfMemoryError.
673 except
= hackTrampoline(2, except
);
675 _Jv_MonitorEnter (this);
676 state
= JV_STATE_ERROR
;
679 _Jv_MonitorExit (this);
687 // Some class-related convenience functions.
690 // Find a method declared in the class. If it is not declared locally
691 // (or if it is inherited), return NULL.
693 _Jv_GetMethodLocal (jclass klass
, _Jv_Utf8Const
*name
,
694 _Jv_Utf8Const
*signature
)
696 for (int i
= 0; i
< klass
->method_count
; ++i
)
698 if (_Jv_equalUtf8Consts (name
, klass
->methods
[i
].name
)
699 && _Jv_equalUtf8Consts (signature
, klass
->methods
[i
].signature
))
700 return &klass
->methods
[i
];
706 _Jv_LookupDeclaredMethod (jclass klass
, _Jv_Utf8Const
*name
,
707 _Jv_Utf8Const
*signature
)
709 for (; klass
; klass
= klass
->getSuperclass())
711 _Jv_Method
*meth
= _Jv_GetMethodLocal (klass
, name
, signature
);
720 // NOTE: MCACHE_SIZE should be a power of 2 minus one.
721 #define MCACHE_SIZE 1023
729 static _Jv_mcache method_cache
[MCACHE_SIZE
+ 1];
732 _Jv_FindMethodInCache (jclass klass
,
734 _Jv_Utf8Const
*signature
)
736 int index
= name
->hash
& MCACHE_SIZE
;
737 _Jv_mcache
*mc
= method_cache
+ index
;
738 _Jv_Method
*m
= mc
->method
;
740 if (mc
->klass
== klass
741 && m
!= NULL
// thread safe check
742 && _Jv_equalUtf8Consts (m
->name
, name
)
743 && _Jv_equalUtf8Consts (m
->signature
, signature
))
744 return mc
->method
->ncode
;
749 _Jv_AddMethodToCache (jclass klass
,
752 _Jv_MonitorEnter (&ClassClass
);
754 int index
= method
->name
->hash
& MCACHE_SIZE
;
756 method_cache
[index
].method
= method
;
757 method_cache
[index
].klass
= klass
;
759 _Jv_MonitorExit (&ClassClass
);
763 _Jv_LookupInterfaceMethod (jclass klass
, _Jv_Utf8Const
*name
,
764 _Jv_Utf8Const
*signature
)
766 void *ncode
= _Jv_FindMethodInCache (klass
, name
, signature
);
770 for (; klass
; klass
= klass
->getSuperclass())
772 _Jv_Method
*meth
= _Jv_GetMethodLocal (klass
, name
, signature
);
776 if (java::lang::reflect::Modifier::isStatic(meth
->accflags
))
777 JvThrow (new java::lang::IncompatibleClassChangeError
);
778 if (java::lang::reflect::Modifier::isAbstract(meth
->accflags
))
779 JvThrow (new java::lang::AbstractMethodError
);
780 if (! java::lang::reflect::Modifier::isPublic(meth
->accflags
))
781 JvThrow (new java::lang::IllegalAccessError
);
783 _Jv_AddMethodToCache (klass
, meth
);
787 JvThrow (new java::lang::IncompatibleClassChangeError
);
788 return NULL
; // Placate compiler.
792 _Jv_InitClass (jclass klass
)
794 klass
->initializeClass();
798 _Jv_IsInstanceOf(jobject obj
, jclass cl
)
800 return cl
->isInstance(obj
);