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