]>
Commit | Line | Data |
---|---|---|
58eb6e7c AG |
1 | // resolve.cc - Code for linking and resolving classes and pool entries. |
2 | ||
4c98b1b0 | 3 | /* Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation |
58eb6e7c AG |
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 | /* Author: Kresten Krab Thorup <krab@gnu.org> */ | |
12 | ||
27e934d8 | 13 | #include <config.h> |
2b7f1f8f | 14 | #include <platform.h> |
27e934d8 | 15 | |
58eb6e7c AG |
16 | #include <java-interp.h> |
17 | ||
58eb6e7c | 18 | #include <jvm.h> |
27e934d8 | 19 | #include <gcj/cni.h> |
58eb6e7c AG |
20 | #include <string.h> |
21 | #include <java-cpool.h> | |
22 | #include <java/lang/Class.h> | |
23 | #include <java/lang/String.h> | |
fd44a92d | 24 | #include <java/lang/StringBuffer.h> |
58eb6e7c AG |
25 | #include <java/lang/Thread.h> |
26 | #include <java/lang/InternalError.h> | |
27 | #include <java/lang/VirtualMachineError.h> | |
28 | #include <java/lang/NoSuchFieldError.h> | |
ddf0fc6c | 29 | #include <java/lang/NoSuchMethodError.h> |
58eb6e7c AG |
30 | #include <java/lang/ClassFormatError.h> |
31 | #include <java/lang/IllegalAccessError.h> | |
32 | #include <java/lang/AbstractMethodError.h> | |
169f75f3 | 33 | #include <java/lang/NoClassDefFoundError.h> |
58eb6e7c | 34 | #include <java/lang/IncompatibleClassChangeError.h> |
b9f42bb0 | 35 | #include <java/lang/VMClassLoader.h> |
e409a2c8 | 36 | #include <java/lang/reflect/Modifier.h> |
58eb6e7c | 37 | |
107abb2f BM |
38 | using namespace gcj; |
39 | ||
83c64db6 TT |
40 | void |
41 | _Jv_ResolveField (_Jv_Field *field, java::lang::ClassLoader *loader) | |
42 | { | |
43 | if (! field->isResolved ()) | |
44 | { | |
45 | _Jv_Utf8Const *sig = (_Jv_Utf8Const*)field->type; | |
46 | field->type = _Jv_FindClassFromSignature (sig->data, loader); | |
47 | field->flags &= ~_Jv_FIELD_UNRESOLVED_FLAG; | |
48 | } | |
49 | } | |
50 | ||
eb4534a6 KKT |
51 | #ifdef INTERPRETER |
52 | ||
58eb6e7c AG |
53 | static void throw_internal_error (char *msg) |
54 | __attribute__ ((__noreturn__)); | |
55 | static void throw_class_format_error (jstring msg) | |
56 | __attribute__ ((__noreturn__)); | |
57 | static void throw_class_format_error (char *msg) | |
58 | __attribute__ ((__noreturn__)); | |
59 | ||
58eb6e7c AG |
60 | static int get_alignment_from_class (jclass); |
61 | ||
62 | static _Jv_ResolvedMethod* | |
63 | _Jv_BuildResolvedMethod (_Jv_Method*, | |
64 | jclass, | |
65 | jboolean, | |
66 | jint); | |
67 | ||
68 | ||
58eb6e7c AG |
69 | static void throw_incompatible_class_change_error (jstring msg) |
70 | { | |
b3208f56 | 71 | throw new java::lang::IncompatibleClassChangeError (msg); |
58eb6e7c AG |
72 | } |
73 | ||
7941ceab | 74 | _Jv_word |
58eb6e7c AG |
75 | _Jv_ResolvePoolEntry (jclass klass, int index) |
76 | { | |
e409a2c8 TT |
77 | using namespace java::lang::reflect; |
78 | ||
58eb6e7c AG |
79 | _Jv_Constants *pool = &klass->constants; |
80 | ||
81 | if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0) | |
82 | return pool->data[index]; | |
83 | ||
84 | switch (pool->tags[index]) { | |
85 | case JV_CONSTANT_Class: | |
86 | { | |
7941ceab | 87 | _Jv_Utf8Const *name = pool->data[index].utf8; |
58eb6e7c AG |
88 | |
89 | jclass found; | |
90 | if (name->data[0] == '[') | |
91 | found = _Jv_FindClassFromSignature (&name->data[0], | |
92 | klass->loader); | |
93 | else | |
94 | found = _Jv_FindClass (name, klass->loader); | |
95 | ||
96 | if (! found) | |
97 | { | |
98 | jstring str = _Jv_NewStringUTF (name->data); | |
169f75f3 TT |
99 | // This exception is specified in JLS 2nd Ed, section 5.1. |
100 | throw new java::lang::NoClassDefFoundError (str); | |
58eb6e7c AG |
101 | } |
102 | ||
e409a2c8 | 103 | if ((found->accflags & Modifier::PUBLIC) == Modifier::PUBLIC |
58eb6e7c AG |
104 | || (_Jv_ClassNameSamePackage (found->name, |
105 | klass->name))) | |
106 | { | |
7941ceab | 107 | pool->data[index].clazz = found; |
58eb6e7c AG |
108 | pool->tags[index] |= JV_CONSTANT_ResolvedFlag; |
109 | } | |
110 | else | |
111 | { | |
b3208f56 | 112 | throw new java::lang::IllegalAccessError (found->getName()); |
58eb6e7c AG |
113 | } |
114 | } | |
115 | break; | |
116 | ||
117 | case JV_CONSTANT_String: | |
118 | { | |
119 | jstring str; | |
7941ceab AG |
120 | str = _Jv_NewStringUtf8Const (pool->data[index].utf8); |
121 | pool->data[index].o = str; | |
58eb6e7c AG |
122 | pool->tags[index] |= JV_CONSTANT_ResolvedFlag; |
123 | } | |
124 | break; | |
125 | ||
eb4534a6 | 126 | |
58eb6e7c AG |
127 | case JV_CONSTANT_Fieldref: |
128 | { | |
129 | _Jv_ushort class_index, name_and_type_index; | |
7941ceab | 130 | _Jv_loadIndexes (&pool->data[index], |
58eb6e7c AG |
131 | class_index, |
132 | name_and_type_index); | |
7941ceab | 133 | jclass owner = (_Jv_ResolvePoolEntry (klass, class_index)).clazz; |
58eb6e7c AG |
134 | |
135 | if (owner != klass) | |
136 | _Jv_InitClass (owner); | |
137 | ||
138 | _Jv_ushort name_index, type_index; | |
7941ceab | 139 | _Jv_loadIndexes (&pool->data[name_and_type_index], |
58eb6e7c AG |
140 | name_index, |
141 | type_index); | |
142 | ||
7941ceab AG |
143 | _Jv_Utf8Const *field_name = pool->data[name_index].utf8; |
144 | _Jv_Utf8Const *field_type_name = pool->data[type_index].utf8; | |
58eb6e7c AG |
145 | |
146 | // FIXME: The implementation of this function | |
147 | // (_Jv_FindClassFromSignature) will generate an instance of | |
148 | // _Jv_Utf8Const for each call if the field type is a class name | |
149 | // (Lxx.yy.Z;). This may be too expensive to do for each and | |
150 | // every fieldref being resolved. For now, we fix the problem by | |
151 | // only doing it when we have a loader different from the class | |
152 | // declaring the field. | |
153 | ||
154 | jclass field_type = 0; | |
155 | ||
156 | if (owner->loader != klass->loader) | |
157 | field_type = _Jv_FindClassFromSignature (field_type_name->data, | |
158 | klass->loader); | |
159 | ||
160 | _Jv_Field* the_field = 0; | |
161 | ||
162 | for (jclass cls = owner; cls != 0; cls = cls->getSuperclass ()) | |
163 | { | |
164 | for (int i = 0; i < cls->field_count; i++) | |
165 | { | |
166 | _Jv_Field *field = &cls->fields[i]; | |
167 | if (! _Jv_equalUtf8Consts (field->name, field_name)) | |
168 | continue; | |
169 | ||
ffd94572 | 170 | if (_Jv_CheckAccess (klass, cls, field->flags)) |
58eb6e7c AG |
171 | { |
172 | /* resove the field using the class' own loader | |
173 | if necessary */ | |
174 | ||
175 | if (!field->isResolved ()) | |
176 | _Jv_ResolveField (field, cls->loader); | |
177 | ||
178 | if (field_type != 0 && field->type != field_type) | |
b3208f56 RH |
179 | throw new java::lang::LinkageError |
180 | (JvNewStringLatin1 | |
181 | ("field type mismatch with different loaders")); | |
58eb6e7c AG |
182 | |
183 | the_field = field; | |
184 | goto end_of_field_search; | |
185 | } | |
186 | else | |
187 | { | |
b3208f56 | 188 | throw new java::lang::IllegalAccessError; |
58eb6e7c AG |
189 | } |
190 | } | |
191 | } | |
192 | ||
193 | end_of_field_search: | |
194 | if (the_field == 0) | |
195 | { | |
fd44a92d TT |
196 | java::lang::StringBuffer *sb = new java::lang::StringBuffer(); |
197 | sb->append(JvNewStringLatin1("field ")); | |
198 | sb->append(owner->getName()); | |
199 | sb->append(JvNewStringLatin1(".")); | |
200 | sb->append(_Jv_NewStringUTF(field_name->data)); | |
201 | sb->append(JvNewStringLatin1(" was not found.")); | |
202 | throw_incompatible_class_change_error(sb->toString()); | |
58eb6e7c AG |
203 | } |
204 | ||
7941ceab | 205 | pool->data[index].field = the_field; |
58eb6e7c AG |
206 | pool->tags[index] |= JV_CONSTANT_ResolvedFlag; |
207 | } | |
208 | break; | |
209 | ||
210 | case JV_CONSTANT_Methodref: | |
211 | case JV_CONSTANT_InterfaceMethodref: | |
212 | { | |
213 | _Jv_ushort class_index, name_and_type_index; | |
7941ceab | 214 | _Jv_loadIndexes (&pool->data[index], |
58eb6e7c AG |
215 | class_index, |
216 | name_and_type_index); | |
7941ceab | 217 | jclass owner = (_Jv_ResolvePoolEntry (klass, class_index)).clazz; |
58eb6e7c AG |
218 | |
219 | if (owner != klass) | |
220 | _Jv_InitClass (owner); | |
221 | ||
222 | _Jv_ushort name_index, type_index; | |
7941ceab | 223 | _Jv_loadIndexes (&pool->data[name_and_type_index], |
58eb6e7c AG |
224 | name_index, |
225 | type_index); | |
226 | ||
7941ceab AG |
227 | _Jv_Utf8Const *method_name = pool->data[name_index].utf8; |
228 | _Jv_Utf8Const *method_signature = pool->data[type_index].utf8; | |
58eb6e7c | 229 | |
58eb6e7c AG |
230 | _Jv_Method *the_method = 0; |
231 | jclass found_class = 0; | |
232 | ||
ddf0fc6c BM |
233 | // First search the class itself. |
234 | the_method = _Jv_SearchMethodInClass (owner, klass, | |
a1aba4f9 | 235 | method_name, method_signature); |
58eb6e7c | 236 | |
ddf0fc6c BM |
237 | if (the_method != 0) |
238 | { | |
239 | found_class = owner; | |
240 | goto end_of_method_search; | |
241 | } | |
58eb6e7c | 242 | |
a1aba4f9 TT |
243 | // If we are resolving an interface method, search the |
244 | // interface's superinterfaces (A superinterface is not an | |
245 | // interface's superclass - a superinterface is implemented by | |
246 | // the interface). | |
ddf0fc6c BM |
247 | if (pool->tags[index] == JV_CONSTANT_InterfaceMethodref) |
248 | { | |
249 | _Jv_ifaces ifaces; | |
250 | ifaces.count = 0; | |
251 | ifaces.len = 4; | |
252 | ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *)); | |
253 | ||
254 | _Jv_GetInterfaces (owner, &ifaces); | |
a1aba4f9 TT |
255 | |
256 | for (int i = 0; i < ifaces.count; i++) | |
ddf0fc6c BM |
257 | { |
258 | jclass cls = ifaces.list[i]; | |
259 | the_method = _Jv_SearchMethodInClass (cls, klass, method_name, | |
260 | method_signature); | |
261 | if (the_method != 0) | |
262 | { | |
58eb6e7c | 263 | found_class = cls; |
ddf0fc6c | 264 | break; |
58eb6e7c AG |
265 | } |
266 | } | |
a1aba4f9 | 267 | |
ddf0fc6c | 268 | _Jv_Free (ifaces.list); |
a1aba4f9 | 269 | |
ddf0fc6c BM |
270 | if (the_method != 0) |
271 | goto end_of_method_search; | |
272 | } | |
273 | ||
274 | // Finally, search superclasses. | |
275 | for (jclass cls = owner->getSuperclass (); cls != 0; | |
276 | cls = cls->getSuperclass ()) | |
277 | { | |
278 | the_method = _Jv_SearchMethodInClass (cls, klass, | |
a1aba4f9 | 279 | method_name, method_signature); |
ddf0fc6c BM |
280 | if (the_method != 0) |
281 | { | |
282 | found_class = cls; | |
283 | break; | |
284 | } | |
58eb6e7c AG |
285 | } |
286 | ||
287 | end_of_method_search: | |
ddf0fc6c BM |
288 | |
289 | // FIXME: if (cls->loader != klass->loader), then we | |
290 | // must actually check that the types of arguments | |
291 | // correspond. That is, for each argument type, and | |
292 | // the return type, doing _Jv_FindClassFromSignature | |
293 | // with either loader should produce the same result, | |
294 | // i.e., exactly the same jclass object. JVMS 5.4.3.3 | |
295 | ||
58eb6e7c AG |
296 | if (the_method == 0) |
297 | { | |
fd44a92d TT |
298 | java::lang::StringBuffer *sb = new java::lang::StringBuffer(); |
299 | sb->append(JvNewStringLatin1("method ")); | |
300 | sb->append(owner->getName()); | |
301 | sb->append(JvNewStringLatin1(".")); | |
302 | sb->append(_Jv_NewStringUTF(method_name->data)); | |
303 | sb->append(JvNewStringLatin1(" was not found.")); | |
304 | throw new java::lang::NoSuchMethodError (sb->toString()); | |
58eb6e7c AG |
305 | } |
306 | ||
a5db0683 JS |
307 | int vtable_index = -1; |
308 | if (pool->tags[index] != JV_CONSTANT_InterfaceMethodref) | |
309 | vtable_index = (jshort)the_method->index; | |
8848a766 | 310 | |
7941ceab | 311 | pool->data[index].rmethod = |
58eb6e7c AG |
312 | _Jv_BuildResolvedMethod(the_method, |
313 | found_class, | |
e409a2c8 | 314 | (the_method->accflags & Modifier::STATIC) != 0, |
58eb6e7c AG |
315 | vtable_index); |
316 | pool->tags[index] |= JV_CONSTANT_ResolvedFlag; | |
317 | } | |
318 | break; | |
319 | ||
320 | } | |
321 | ||
322 | return pool->data[index]; | |
323 | } | |
324 | ||
ddf0fc6c BM |
325 | // Find a method declared in the cls that is referenced from klass and |
326 | // perform access checks. | |
327 | _Jv_Method * | |
328 | _Jv_SearchMethodInClass (jclass cls, jclass klass, | |
329 | _Jv_Utf8Const *method_name, | |
330 | _Jv_Utf8Const *method_signature) | |
331 | { | |
332 | using namespace java::lang::reflect; | |
333 | ||
334 | for (int i = 0; i < cls->method_count; i++) | |
335 | { | |
336 | _Jv_Method *method = &cls->methods[i]; | |
337 | if ( (!_Jv_equalUtf8Consts (method->name, | |
338 | method_name)) | |
339 | || (!_Jv_equalUtf8Consts (method->signature, | |
340 | method_signature))) | |
341 | continue; | |
342 | ||
ffd94572 TT |
343 | if (_Jv_CheckAccess (klass, cls, method->accflags)) |
344 | return method; | |
ddf0fc6c | 345 | else |
ffd94572 | 346 | throw new java::lang::IllegalAccessError; |
ddf0fc6c BM |
347 | } |
348 | return 0; | |
349 | } | |
eb4534a6 | 350 | |
a1aba4f9 TT |
351 | // A helper for _Jv_PrepareClass. This adds missing `Miranda methods' |
352 | // to a class. | |
353 | void | |
354 | _Jv_PrepareMissingMethods (jclass base2, jclass iface_class) | |
355 | { | |
356 | _Jv_InterpClass *base = reinterpret_cast<_Jv_InterpClass *> (base2); | |
357 | for (int i = 0; i < iface_class->interface_count; ++i) | |
358 | { | |
359 | for (int j = 0; j < iface_class->interfaces[i]->method_count; ++j) | |
360 | { | |
361 | _Jv_Method *meth = &iface_class->interfaces[i]->methods[j]; | |
362 | // Don't bother with <clinit>. | |
363 | if (meth->name->data[0] == '<') | |
364 | continue; | |
365 | _Jv_Method *new_meth = _Jv_LookupDeclaredMethod (base, meth->name, | |
366 | meth->signature); | |
367 | if (! new_meth) | |
368 | { | |
369 | // We assume that such methods are very unlikely, so we | |
370 | // just reallocate the method array each time one is | |
371 | // found. This greatly simplifies the searching -- | |
372 | // otherwise we have to make sure that each such method | |
373 | // found is really unique among all superinterfaces. | |
374 | int new_count = base->method_count + 1; | |
375 | _Jv_Method *new_m | |
376 | = (_Jv_Method *) _Jv_AllocBytes (sizeof (_Jv_Method) | |
377 | * new_count); | |
378 | memcpy (new_m, base->methods, | |
379 | sizeof (_Jv_Method) * base->method_count); | |
380 | ||
381 | // Add new method. | |
382 | new_m[base->method_count] = *meth; | |
383 | new_m[base->method_count].index = (_Jv_ushort) -1; | |
384 | new_m[base->method_count].accflags | |
385 | |= java::lang::reflect::Modifier::INVISIBLE; | |
386 | ||
387 | _Jv_MethodBase **new_im | |
388 | = (_Jv_MethodBase **) _Jv_AllocBytes (sizeof (_Jv_MethodBase *) | |
389 | * new_count); | |
390 | memcpy (new_im, base->interpreted_methods, | |
391 | sizeof (_Jv_MethodBase *) * base->method_count); | |
392 | ||
393 | base->methods = new_m; | |
394 | base->interpreted_methods = new_im; | |
395 | base->method_count = new_count; | |
396 | } | |
397 | } | |
398 | ||
399 | _Jv_PrepareMissingMethods (base, iface_class->interfaces[i]); | |
400 | } | |
401 | } | |
402 | ||
58eb6e7c AG |
403 | void |
404 | _Jv_PrepareClass(jclass klass) | |
405 | { | |
e409a2c8 TT |
406 | using namespace java::lang::reflect; |
407 | ||
58eb6e7c AG |
408 | /* |
409 | * The job of this function is to: 1) assign storage to fields, and 2) | |
410 | * build the vtable. static fields are assigned real memory, instance | |
411 | * fields are assigned offsets. | |
412 | * | |
413 | * NOTE: we have a contract with the garbage collector here. Static | |
414 | * reference fields must not be resolved, until after they have storage | |
415 | * assigned which is the check used by the collector to see if it | |
416 | * should indirect the static field reference and mark the object | |
417 | * pointed to. | |
418 | * | |
419 | * Most fields are resolved lazily (i.e. have their class-type | |
420 | * assigned) when they are accessed the first time by calling as part | |
421 | * of _Jv_ResolveField, which is allways called after _Jv_PrepareClass. | |
422 | * Static fields with initializers are resolved as part of this | |
423 | * function, as are fields with primitive types. | |
424 | */ | |
425 | ||
426 | if (! _Jv_IsInterpretedClass (klass)) | |
427 | return; | |
428 | ||
429 | if (klass->state >= JV_STATE_PREPARED) | |
430 | return; | |
431 | ||
04a704a4 TT |
432 | // Make sure super-class is linked. This involves taking a lock on |
433 | // the super class, so we use the Java method resolveClass, which | |
434 | // will unlock it properly, should an exception happen. If there's | |
435 | // no superclass, do nothing -- Object will already have been | |
436 | // resolved. | |
58eb6e7c | 437 | |
04a704a4 | 438 | if (klass->superclass) |
b9f42bb0 | 439 | java::lang::VMClassLoader::resolveClass (klass->superclass); |
58eb6e7c AG |
440 | |
441 | _Jv_InterpClass *clz = (_Jv_InterpClass*)klass; | |
442 | ||
443 | /************ PART ONE: OBJECT LAYOUT ***************/ | |
444 | ||
5940c2b7 TT |
445 | // Compute the alignment for this type by searching through the |
446 | // superclasses and finding the maximum required alignment. We | |
447 | // could consider caching this in the Class. | |
448 | int max_align = __alignof__ (java::lang::Object); | |
449 | jclass super = clz->superclass; | |
450 | while (super != NULL) | |
451 | { | |
452 | int num = JvNumInstanceFields (super); | |
453 | _Jv_Field *field = JvGetFirstInstanceField (super); | |
454 | while (num > 0) | |
455 | { | |
456 | int field_align = get_alignment_from_class (field->type); | |
457 | if (field_align > max_align) | |
458 | max_align = field_align; | |
459 | ++field; | |
460 | --num; | |
461 | } | |
462 | super = super->superclass; | |
463 | } | |
464 | ||
58eb6e7c | 465 | int instance_size; |
5940c2b7 | 466 | int static_size = 0; |
58eb6e7c | 467 | |
04a704a4 | 468 | // Although java.lang.Object is never interpreted, an interface can |
5940c2b7 TT |
469 | // have a null superclass. Note that we have to lay out an |
470 | // interface because it might have static fields. | |
04a704a4 TT |
471 | if (clz->superclass) |
472 | instance_size = clz->superclass->size(); | |
473 | else | |
474 | instance_size = java::lang::Object::class$.size(); | |
58eb6e7c AG |
475 | |
476 | for (int i = 0; i < clz->field_count; i++) | |
477 | { | |
478 | int field_size; | |
479 | int field_align; | |
480 | ||
481 | _Jv_Field *field = &clz->fields[i]; | |
482 | ||
483 | if (! field->isRef ()) | |
484 | { | |
485 | // it's safe to resolve the field here, since it's | |
486 | // a primitive class, which does not cause loading to happen. | |
487 | _Jv_ResolveField (field, clz->loader); | |
488 | ||
489 | field_size = field->type->size (); | |
490 | field_align = get_alignment_from_class (field->type); | |
491 | } | |
492 | else | |
493 | { | |
494 | field_size = sizeof (jobject); | |
495 | field_align = __alignof__ (jobject); | |
496 | } | |
497 | ||
498 | #ifndef COMPACT_FIELDS | |
499 | field->bsize = field_size; | |
500 | #endif | |
501 | ||
e409a2c8 | 502 | if (field->flags & Modifier::STATIC) |
58eb6e7c AG |
503 | { |
504 | /* this computes an offset into a region we'll allocate | |
505 | shortly, and then add this offset to the start address */ | |
506 | ||
507 | static_size = ROUND (static_size, field_align); | |
508 | field->u.boffset = static_size; | |
509 | static_size += field_size; | |
510 | } | |
511 | else | |
512 | { | |
513 | instance_size = ROUND (instance_size, field_align); | |
514 | field->u.boffset = instance_size; | |
515 | instance_size += field_size; | |
5940c2b7 TT |
516 | if (field_align > max_align) |
517 | max_align = field_align; | |
58eb6e7c AG |
518 | } |
519 | } | |
520 | ||
355d8993 | 521 | // Set the instance size for the class. Note that first we round it |
5940c2b7 TT |
522 | // to the alignment required for this object; this keeps us in sync |
523 | // with our current ABI. | |
524 | instance_size = ROUND (instance_size, max_align); | |
58eb6e7c | 525 | clz->size_in_bytes = instance_size; |
6d8b1244 | 526 | |
58eb6e7c AG |
527 | // allocate static memory |
528 | if (static_size != 0) | |
529 | { | |
3610e0d5 | 530 | char *static_data = (char*)_Jv_AllocBytes (static_size); |
58eb6e7c AG |
531 | |
532 | memset (static_data, 0, static_size); | |
533 | ||
534 | for (int i = 0; i < clz->field_count; i++) | |
535 | { | |
536 | _Jv_Field *field = &clz->fields[i]; | |
537 | ||
e409a2c8 | 538 | if ((field->flags & Modifier::STATIC) != 0) |
58eb6e7c AG |
539 | { |
540 | field->u.addr = static_data + field->u.boffset; | |
541 | ||
542 | if (clz->field_initializers[i] != 0) | |
543 | { | |
544 | _Jv_ResolveField (field, clz->loader); | |
545 | _Jv_InitField (0, clz, i); | |
546 | } | |
547 | } | |
548 | } | |
549 | ||
550 | // now we don't need the field_initializers anymore, so let the | |
551 | // collector get rid of it! | |
552 | ||
553 | clz->field_initializers = 0; | |
554 | } | |
555 | ||
556 | /************ PART TWO: VTABLE LAYOUT ***************/ | |
557 | ||
558 | /* preparation: build the vtable stubs (even interfaces can) | |
559 | have code -- for static constructors. */ | |
560 | for (int i = 0; i < clz->method_count; i++) | |
561 | { | |
facc279f | 562 | _Jv_MethodBase *imeth = clz->interpreted_methods[i]; |
58eb6e7c | 563 | |
facc279f | 564 | if ((clz->methods[i].accflags & Modifier::NATIVE) != 0) |
58eb6e7c | 565 | { |
facc279f TT |
566 | // You might think we could use a virtual `ncode' method in |
567 | // the _Jv_MethodBase and unify the native and non-native | |
568 | // cases. Well, we can't, because we don't allocate these | |
569 | // objects using `new', and thus they don't get a vtable. | |
570 | _Jv_JNIMethod *jnim = reinterpret_cast<_Jv_JNIMethod *> (imeth); | |
571 | clz->methods[i].ncode = jnim->ncode (); | |
58eb6e7c | 572 | } |
facc279f | 573 | else if (imeth != 0) // it could be abstract |
58eb6e7c | 574 | { |
715bdd81 | 575 | _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (imeth); |
bd917d3a | 576 | _Jv_VerifyMethod (im); |
facc279f | 577 | clz->methods[i].ncode = im->ncode (); |
90471585 AH |
578 | |
579 | // Resolve ctable entries pointing to this method. See | |
580 | // _Jv_Defer_Resolution. | |
581 | void **code = (void **)imeth->deferred; | |
582 | while (code) | |
583 | { | |
584 | void **target = (void **)*code; | |
585 | *code = clz->methods[i].ncode; | |
586 | code = target; | |
587 | } | |
58eb6e7c AG |
588 | } |
589 | } | |
590 | ||
a1aba4f9 | 591 | if ((clz->accflags & Modifier::INTERFACE)) |
58eb6e7c AG |
592 | { |
593 | clz->state = JV_STATE_PREPARED; | |
594 | clz->notifyAll (); | |
595 | return; | |
596 | } | |
597 | ||
a1aba4f9 TT |
598 | // A class might have so-called "Miranda methods". This is a method |
599 | // that is declared in an interface and not re-declared in an | |
600 | // abstract class. Some compilers don't emit declarations for such | |
601 | // methods in the class; this will give us problems since we expect | |
602 | // a declaration for any method requiring a vtable entry. We handle | |
603 | // this here by searching for such methods and constructing new | |
604 | // internal declarations for them. We only need to do this for | |
605 | // abstract classes. | |
606 | if ((clz->accflags & Modifier::ABSTRACT)) | |
607 | _Jv_PrepareMissingMethods (clz, clz); | |
608 | ||
a5db0683 JS |
609 | clz->vtable_method_count = -1; |
610 | _Jv_MakeVTable (clz); | |
58eb6e7c AG |
611 | |
612 | /* wooha! we're done. */ | |
613 | clz->state = JV_STATE_PREPARED; | |
614 | clz->notifyAll (); | |
615 | } | |
616 | ||
617 | /** Do static initialization for fields with a constant initializer */ | |
618 | void | |
619 | _Jv_InitField (jobject obj, jclass klass, int index) | |
620 | { | |
e409a2c8 TT |
621 | using namespace java::lang::reflect; |
622 | ||
58eb6e7c AG |
623 | if (obj != 0 && klass == 0) |
624 | klass = obj->getClass (); | |
625 | ||
626 | if (!_Jv_IsInterpretedClass (klass)) | |
627 | return; | |
628 | ||
629 | _Jv_InterpClass *clz = (_Jv_InterpClass*)klass; | |
630 | ||
631 | _Jv_Field * field = (&clz->fields[0]) + index; | |
632 | ||
633 | if (index > clz->field_count) | |
634 | throw_internal_error ("field out of range"); | |
635 | ||
636 | int init = clz->field_initializers[index]; | |
637 | if (init == 0) | |
638 | return; | |
639 | ||
640 | _Jv_Constants *pool = &clz->constants; | |
641 | int tag = pool->tags[init]; | |
642 | ||
643 | if (! field->isResolved ()) | |
644 | throw_internal_error ("initializing unresolved field"); | |
645 | ||
e409a2c8 | 646 | if (obj==0 && ((field->flags & Modifier::STATIC) == 0)) |
58eb6e7c AG |
647 | throw_internal_error ("initializing non-static field with no object"); |
648 | ||
649 | void *addr = 0; | |
650 | ||
e409a2c8 | 651 | if ((field->flags & Modifier::STATIC) != 0) |
58eb6e7c AG |
652 | addr = (void*) field->u.addr; |
653 | else | |
654 | addr = (void*) (((char*)obj) + field->u.boffset); | |
655 | ||
656 | switch (tag) | |
657 | { | |
658 | case JV_CONSTANT_String: | |
659 | { | |
660 | _Jv_MonitorEnter (clz); | |
661 | jstring str; | |
7941ceab AG |
662 | str = _Jv_NewStringUtf8Const (pool->data[init].utf8); |
663 | pool->data[init].string = str; | |
58eb6e7c AG |
664 | pool->tags[init] = JV_CONSTANT_ResolvedString; |
665 | _Jv_MonitorExit (clz); | |
666 | } | |
667 | /* fall through */ | |
668 | ||
669 | case JV_CONSTANT_ResolvedString: | |
1d336a09 TT |
670 | if (! (field->type == &StringClass |
671 | || field->type == &java::lang::Class::class$)) | |
58eb6e7c AG |
672 | throw_class_format_error ("string initialiser to non-string field"); |
673 | ||
7941ceab | 674 | *(jstring*)addr = pool->data[init].string; |
58eb6e7c AG |
675 | break; |
676 | ||
677 | case JV_CONSTANT_Integer: | |
678 | { | |
7941ceab | 679 | int value = pool->data[init].i; |
58eb6e7c AG |
680 | |
681 | if (field->type == JvPrimClass (boolean)) | |
682 | *(jboolean*)addr = (jboolean)value; | |
683 | ||
684 | else if (field->type == JvPrimClass (byte)) | |
685 | *(jbyte*)addr = (jbyte)value; | |
686 | ||
687 | else if (field->type == JvPrimClass (char)) | |
688 | *(jchar*)addr = (jchar)value; | |
689 | ||
690 | else if (field->type == JvPrimClass (short)) | |
691 | *(jshort*)addr = (jshort)value; | |
692 | ||
693 | else if (field->type == JvPrimClass (int)) | |
694 | *(jint*)addr = (jint)value; | |
695 | ||
696 | else | |
697 | throw_class_format_error ("erroneous field initializer"); | |
698 | } | |
699 | break; | |
700 | ||
701 | case JV_CONSTANT_Long: | |
702 | if (field->type != JvPrimClass (long)) | |
703 | throw_class_format_error ("erroneous field initializer"); | |
704 | ||
7941ceab | 705 | *(jlong*)addr = _Jv_loadLong (&pool->data[init]); |
58eb6e7c AG |
706 | break; |
707 | ||
708 | case JV_CONSTANT_Float: | |
709 | if (field->type != JvPrimClass (float)) | |
710 | throw_class_format_error ("erroneous field initializer"); | |
711 | ||
7941ceab | 712 | *(jfloat*)addr = pool->data[init].f; |
58eb6e7c AG |
713 | break; |
714 | ||
715 | case JV_CONSTANT_Double: | |
716 | if (field->type != JvPrimClass (double)) | |
717 | throw_class_format_error ("erroneous field initializer"); | |
718 | ||
7941ceab | 719 | *(jdouble*)addr = _Jv_loadDouble (&pool->data[init]); |
58eb6e7c AG |
720 | break; |
721 | ||
722 | default: | |
723 | throw_class_format_error ("erroneous field initializer"); | |
724 | } | |
725 | } | |
726 | ||
5940c2b7 TT |
727 | template<typename T> |
728 | struct aligner | |
729 | { | |
730 | T field; | |
731 | }; | |
732 | ||
733 | #define ALIGNOF(TYPE) (__alignof__ (((aligner<TYPE> *) 0)->field)) | |
734 | ||
735 | // This returns the alignment of a type as it would appear in a | |
736 | // structure. This can be different from the alignment of the type | |
737 | // itself. For instance on x86 double is 8-aligned but struct{double} | |
738 | // is 4-aligned. | |
58eb6e7c AG |
739 | static int |
740 | get_alignment_from_class (jclass klass) | |
741 | { | |
742 | if (klass == JvPrimClass (byte)) | |
5940c2b7 | 743 | return ALIGNOF (jbyte); |
58eb6e7c | 744 | else if (klass == JvPrimClass (short)) |
5940c2b7 | 745 | return ALIGNOF (jshort); |
58eb6e7c | 746 | else if (klass == JvPrimClass (int)) |
5940c2b7 | 747 | return ALIGNOF (jint); |
58eb6e7c | 748 | else if (klass == JvPrimClass (long)) |
5940c2b7 | 749 | return ALIGNOF (jlong); |
58eb6e7c | 750 | else if (klass == JvPrimClass (boolean)) |
5940c2b7 | 751 | return ALIGNOF (jboolean); |
58eb6e7c | 752 | else if (klass == JvPrimClass (char)) |
5940c2b7 | 753 | return ALIGNOF (jchar); |
58eb6e7c | 754 | else if (klass == JvPrimClass (float)) |
5940c2b7 | 755 | return ALIGNOF (jfloat); |
58eb6e7c | 756 | else if (klass == JvPrimClass (double)) |
5940c2b7 | 757 | return ALIGNOF (jdouble); |
58eb6e7c | 758 | else |
5940c2b7 | 759 | return ALIGNOF (jobject); |
58eb6e7c AG |
760 | } |
761 | ||
762 | ||
763 | inline static unsigned char* | |
764 | skip_one_type (unsigned char* ptr) | |
765 | { | |
766 | int ch = *ptr++; | |
767 | ||
768 | while (ch == '[') | |
769 | { | |
770 | ch = *ptr++; | |
771 | } | |
772 | ||
773 | if (ch == 'L') | |
774 | { | |
775 | do { ch = *ptr++; } while (ch != ';'); | |
776 | } | |
777 | ||
778 | return ptr; | |
779 | } | |
780 | ||
781 | static ffi_type* | |
782 | get_ffi_type_from_signature (unsigned char* ptr) | |
783 | { | |
784 | switch (*ptr) | |
785 | { | |
786 | case 'L': | |
787 | case '[': | |
788 | return &ffi_type_pointer; | |
789 | break; | |
790 | ||
791 | case 'Z': | |
673fdf6d TT |
792 | // On some platforms a bool is a byte, on others an int. |
793 | if (sizeof (jboolean) == sizeof (jbyte)) | |
794 | return &ffi_type_sint8; | |
795 | else | |
796 | { | |
797 | JvAssert (sizeof (jbyte) == sizeof (jint)); | |
798 | return &ffi_type_sint32; | |
799 | } | |
800 | break; | |
801 | ||
58eb6e7c AG |
802 | case 'B': |
803 | return &ffi_type_sint8; | |
804 | break; | |
805 | ||
806 | case 'C': | |
807 | return &ffi_type_uint16; | |
808 | break; | |
809 | ||
810 | case 'S': | |
811 | return &ffi_type_sint16; | |
812 | break; | |
813 | ||
814 | case 'I': | |
815 | return &ffi_type_sint32; | |
816 | break; | |
817 | ||
818 | case 'J': | |
819 | return &ffi_type_sint64; | |
820 | break; | |
821 | ||
822 | case 'F': | |
823 | return &ffi_type_float; | |
824 | break; | |
825 | ||
826 | case 'D': | |
827 | return &ffi_type_double; | |
828 | break; | |
829 | ||
830 | case 'V': | |
831 | return &ffi_type_void; | |
832 | break; | |
833 | } | |
834 | ||
835 | throw_internal_error ("unknown type in signature"); | |
836 | } | |
837 | ||
838 | /* this function yields the number of actual arguments, that is, if the | |
839 | * function is non-static, then one is added to the number of elements | |
840 | * found in the signature */ | |
841 | ||
a12fe13d TT |
842 | int |
843 | _Jv_count_arguments (_Jv_Utf8Const *signature, | |
844 | jboolean staticp) | |
58eb6e7c AG |
845 | { |
846 | unsigned char *ptr = (unsigned char*) signature->data; | |
847 | int arg_count = staticp ? 0 : 1; | |
848 | ||
849 | /* first, count number of arguments */ | |
850 | ||
851 | // skip '(' | |
852 | ptr++; | |
853 | ||
854 | // count args | |
855 | while (*ptr != ')') | |
856 | { | |
857 | ptr = skip_one_type (ptr); | |
858 | arg_count += 1; | |
859 | } | |
860 | ||
861 | return arg_count; | |
862 | } | |
863 | ||
864 | /* This beast will build a cif, given the signature. Memory for | |
865 | * the cif itself and for the argument types must be allocated by the | |
866 | * caller. | |
867 | */ | |
868 | ||
869 | static int | |
870 | init_cif (_Jv_Utf8Const* signature, | |
871 | int arg_count, | |
872 | jboolean staticp, | |
873 | ffi_cif *cif, | |
d348bda4 TT |
874 | ffi_type **arg_types, |
875 | ffi_type **rtype_p) | |
58eb6e7c AG |
876 | { |
877 | unsigned char *ptr = (unsigned char*) signature->data; | |
878 | ||
879 | int arg_index = 0; // arg number | |
880 | int item_count = 0; // stack-item count | |
881 | ||
882 | // setup receiver | |
883 | if (!staticp) | |
884 | { | |
885 | arg_types[arg_index++] = &ffi_type_pointer; | |
886 | item_count += 1; | |
887 | } | |
888 | ||
889 | // skip '(' | |
890 | ptr++; | |
891 | ||
892 | // assign arg types | |
893 | while (*ptr != ')') | |
894 | { | |
895 | arg_types[arg_index++] = get_ffi_type_from_signature (ptr); | |
896 | ||
897 | if (*ptr == 'J' || *ptr == 'D') | |
898 | item_count += 2; | |
899 | else | |
900 | item_count += 1; | |
901 | ||
902 | ptr = skip_one_type (ptr); | |
903 | } | |
904 | ||
905 | // skip ')' | |
906 | ptr++; | |
907 | ffi_type *rtype = get_ffi_type_from_signature (ptr); | |
908 | ||
909 | ptr = skip_one_type (ptr); | |
910 | if (ptr != (unsigned char*)signature->data + signature->length) | |
911 | throw_internal_error ("did not find end of signature"); | |
912 | ||
913 | if (ffi_prep_cif (cif, FFI_DEFAULT_ABI, | |
914 | arg_count, rtype, arg_types) != FFI_OK) | |
915 | throw_internal_error ("ffi_prep_cif failed"); | |
916 | ||
d348bda4 TT |
917 | if (rtype_p != NULL) |
918 | *rtype_p = rtype; | |
919 | ||
58eb6e7c AG |
920 | return item_count; |
921 | } | |
922 | ||
99444711 TT |
923 | #if FFI_NATIVE_RAW_API |
924 | # define FFI_PREP_RAW_CLOSURE ffi_prep_raw_closure | |
925 | # define FFI_RAW_SIZE ffi_raw_size | |
926 | #else | |
927 | # define FFI_PREP_RAW_CLOSURE ffi_prep_java_raw_closure | |
928 | # define FFI_RAW_SIZE ffi_java_raw_size | |
929 | #endif | |
58eb6e7c AG |
930 | |
931 | /* we put this one here, and not in interpret.cc because it | |
a12fe13d | 932 | * calls the utility routines _Jv_count_arguments |
58eb6e7c AG |
933 | * which are static to this module. The following struct defines the |
934 | * layout we use for the stubs, it's only used in the ncode method. */ | |
935 | ||
936 | typedef struct { | |
937 | ffi_raw_closure closure; | |
938 | ffi_cif cif; | |
939 | ffi_type *arg_types[0]; | |
940 | } ncode_closure; | |
941 | ||
942 | typedef void (*ffi_closure_fun) (ffi_cif*,void*,ffi_raw*,void*); | |
943 | ||
e409a2c8 TT |
944 | void * |
945 | _Jv_InterpMethod::ncode () | |
58eb6e7c | 946 | { |
e409a2c8 TT |
947 | using namespace java::lang::reflect; |
948 | ||
58eb6e7c AG |
949 | if (self->ncode != 0) |
950 | return self->ncode; | |
951 | ||
e409a2c8 | 952 | jboolean staticp = (self->accflags & Modifier::STATIC) != 0; |
a12fe13d | 953 | int arg_count = _Jv_count_arguments (self->signature, staticp); |
58eb6e7c AG |
954 | |
955 | ncode_closure *closure = | |
3610e0d5 | 956 | (ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure) |
58eb6e7c AG |
957 | + arg_count * sizeof (ffi_type*)); |
958 | ||
959 | init_cif (self->signature, | |
960 | arg_count, | |
961 | staticp, | |
962 | &closure->cif, | |
d348bda4 TT |
963 | &closure->arg_types[0], |
964 | NULL); | |
58eb6e7c AG |
965 | |
966 | ffi_closure_fun fun; | |
967 | ||
99444711 | 968 | args_raw_size = FFI_RAW_SIZE (&closure->cif); |
58eb6e7c | 969 | |
facc279f TT |
970 | JvAssert ((self->accflags & Modifier::NATIVE) == 0); |
971 | ||
972 | if ((self->accflags & Modifier::SYNCHRONIZED) != 0) | |
58eb6e7c AG |
973 | { |
974 | if (staticp) | |
975 | fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class; | |
976 | else | |
977 | fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object; | |
978 | } | |
979 | else | |
980 | { | |
4c98b1b0 TT |
981 | if (staticp) |
982 | fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class; | |
983 | else | |
984 | fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal; | |
58eb6e7c AG |
985 | } |
986 | ||
99444711 TT |
987 | FFI_PREP_RAW_CLOSURE (&closure->closure, |
988 | &closure->cif, | |
989 | fun, | |
990 | (void*)this); | |
facc279f TT |
991 | |
992 | self->ncode = (void*)closure; | |
993 | return self->ncode; | |
994 | } | |
995 | ||
facc279f TT |
996 | void * |
997 | _Jv_JNIMethod::ncode () | |
998 | { | |
999 | using namespace java::lang::reflect; | |
1000 | ||
1001 | if (self->ncode != 0) | |
1002 | return self->ncode; | |
1003 | ||
1004 | jboolean staticp = (self->accflags & Modifier::STATIC) != 0; | |
a12fe13d | 1005 | int arg_count = _Jv_count_arguments (self->signature, staticp); |
facc279f TT |
1006 | |
1007 | ncode_closure *closure = | |
3610e0d5 TT |
1008 | (ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure) |
1009 | + arg_count * sizeof (ffi_type*)); | |
facc279f | 1010 | |
d348bda4 | 1011 | ffi_type *rtype; |
facc279f TT |
1012 | init_cif (self->signature, |
1013 | arg_count, | |
1014 | staticp, | |
1015 | &closure->cif, | |
d348bda4 TT |
1016 | &closure->arg_types[0], |
1017 | &rtype); | |
facc279f TT |
1018 | |
1019 | ffi_closure_fun fun; | |
1020 | ||
99444711 | 1021 | args_raw_size = FFI_RAW_SIZE (&closure->cif); |
d348bda4 TT |
1022 | |
1023 | // Initialize the argument types and CIF that represent the actual | |
1024 | // underlying JNI function. | |
1025 | int extra_args = 1; | |
1026 | if ((self->accflags & Modifier::STATIC)) | |
1027 | ++extra_args; | |
1028 | jni_arg_types = (ffi_type **) _Jv_Malloc ((extra_args + arg_count) | |
1029 | * sizeof (ffi_type *)); | |
1030 | int offset = 0; | |
1031 | jni_arg_types[offset++] = &ffi_type_pointer; | |
1032 | if ((self->accflags & Modifier::STATIC)) | |
1033 | jni_arg_types[offset++] = &ffi_type_pointer; | |
1034 | memcpy (&jni_arg_types[offset], &closure->arg_types[0], | |
1035 | arg_count * sizeof (ffi_type *)); | |
1036 | ||
2b7f1f8f | 1037 | if (ffi_prep_cif (&jni_cif, _Jv_platform_ffi_abi, |
d348bda4 TT |
1038 | extra_args + arg_count, rtype, |
1039 | jni_arg_types) != FFI_OK) | |
1040 | throw_internal_error ("ffi_prep_cif failed for JNI function"); | |
1041 | ||
facc279f TT |
1042 | JvAssert ((self->accflags & Modifier::NATIVE) != 0); |
1043 | ||
1044 | // FIXME: for now we assume that all native methods for | |
1045 | // interpreted code use JNI. | |
1046 | fun = (ffi_closure_fun) &_Jv_JNIMethod::call; | |
1047 | ||
99444711 | 1048 | FFI_PREP_RAW_CLOSURE (&closure->closure, |
facc279f TT |
1049 | &closure->cif, |
1050 | fun, | |
1051 | (void*) this); | |
58eb6e7c | 1052 | |
d348bda4 | 1053 | self->ncode = (void *) closure; |
58eb6e7c AG |
1054 | return self->ncode; |
1055 | } | |
1056 | ||
1057 | ||
1058 | /* A _Jv_ResolvedMethod is what is put in the constant pool for a | |
1059 | * MethodRef or InterfacemethodRef. */ | |
1060 | static _Jv_ResolvedMethod* | |
1061 | _Jv_BuildResolvedMethod (_Jv_Method* method, | |
1062 | jclass klass, | |
1063 | jboolean staticp, | |
1064 | jint vtable_index) | |
1065 | { | |
a12fe13d | 1066 | int arg_count = _Jv_count_arguments (method->signature, staticp); |
58eb6e7c AG |
1067 | |
1068 | _Jv_ResolvedMethod* result = (_Jv_ResolvedMethod*) | |
3610e0d5 TT |
1069 | _Jv_AllocBytes (sizeof (_Jv_ResolvedMethod) |
1070 | + arg_count*sizeof (ffi_type*)); | |
58eb6e7c AG |
1071 | |
1072 | result->stack_item_count | |
1073 | = init_cif (method->signature, | |
1074 | arg_count, | |
1075 | staticp, | |
1076 | &result->cif, | |
d348bda4 TT |
1077 | &result->arg_types[0], |
1078 | NULL); | |
58eb6e7c AG |
1079 | |
1080 | result->vtable_index = vtable_index; | |
1081 | result->method = method; | |
1082 | result->klass = klass; | |
1083 | ||
1084 | return result; | |
1085 | } | |
1086 | ||
1087 | ||
1088 | static void | |
1089 | throw_class_format_error (jstring msg) | |
1090 | { | |
b3208f56 RH |
1091 | throw (msg |
1092 | ? new java::lang::ClassFormatError (msg) | |
1093 | : new java::lang::ClassFormatError); | |
58eb6e7c AG |
1094 | } |
1095 | ||
1096 | static void | |
1097 | throw_class_format_error (char *msg) | |
1098 | { | |
1099 | throw_class_format_error (JvNewStringLatin1 (msg)); | |
1100 | } | |
1101 | ||
1102 | static void | |
1103 | throw_internal_error (char *msg) | |
1104 | { | |
b3208f56 | 1105 | throw new java::lang::InternalError (JvNewStringLatin1 (msg)); |
58eb6e7c AG |
1106 | } |
1107 | ||
1108 | ||
e409a2c8 | 1109 | #endif /* INTERPRETER */ |