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