]>
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 | ||
58eb6e7c AG |
44 | #define ClassObject _CL_Q34java4lang6Object |
45 | extern java::lang::Class ClassObject; | |
46 | #define ObjectClass _CL_Q34java4lang6Object | |
47 | extern java::lang::Class ObjectClass; | |
48 | ||
49 | ||
50 | static int get_alignment_from_class (jclass); | |
51 | ||
52 | static _Jv_ResolvedMethod* | |
53 | _Jv_BuildResolvedMethod (_Jv_Method*, | |
54 | jclass, | |
55 | jboolean, | |
56 | jint); | |
57 | ||
58 | ||
58eb6e7c AG |
59 | // We need to know the name of a constructor. |
60 | static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6); | |
61 | ||
62 | static void throw_incompatible_class_change_error (jstring msg) | |
63 | { | |
64 | JvThrow (new java::lang::IncompatibleClassChangeError (msg)); | |
65 | } | |
66 | ||
7941ceab | 67 | _Jv_word |
58eb6e7c AG |
68 | _Jv_ResolvePoolEntry (jclass klass, int index) |
69 | { | |
e409a2c8 TT |
70 | using namespace java::lang::reflect; |
71 | ||
58eb6e7c AG |
72 | _Jv_Constants *pool = &klass->constants; |
73 | ||
74 | if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0) | |
75 | return pool->data[index]; | |
76 | ||
77 | switch (pool->tags[index]) { | |
78 | case JV_CONSTANT_Class: | |
79 | { | |
7941ceab | 80 | _Jv_Utf8Const *name = pool->data[index].utf8; |
58eb6e7c AG |
81 | |
82 | jclass found; | |
83 | if (name->data[0] == '[') | |
84 | found = _Jv_FindClassFromSignature (&name->data[0], | |
85 | klass->loader); | |
86 | else | |
87 | found = _Jv_FindClass (name, klass->loader); | |
88 | ||
89 | if (! found) | |
90 | { | |
91 | jstring str = _Jv_NewStringUTF (name->data); | |
92 | JvThrow (new java::lang::ClassNotFoundException (str)); | |
93 | } | |
94 | ||
e409a2c8 | 95 | if ((found->accflags & Modifier::PUBLIC) == Modifier::PUBLIC |
58eb6e7c AG |
96 | || (_Jv_ClassNameSamePackage (found->name, |
97 | klass->name))) | |
98 | { | |
7941ceab | 99 | pool->data[index].clazz = found; |
58eb6e7c AG |
100 | pool->tags[index] |= JV_CONSTANT_ResolvedFlag; |
101 | } | |
102 | else | |
103 | { | |
104 | JvThrow (new java::lang::IllegalAccessError (found->getName())); | |
105 | } | |
106 | } | |
107 | break; | |
108 | ||
109 | case JV_CONSTANT_String: | |
110 | { | |
111 | jstring str; | |
7941ceab AG |
112 | str = _Jv_NewStringUtf8Const (pool->data[index].utf8); |
113 | pool->data[index].o = str; | |
58eb6e7c AG |
114 | pool->tags[index] |= JV_CONSTANT_ResolvedFlag; |
115 | } | |
116 | break; | |
117 | ||
eb4534a6 | 118 | |
58eb6e7c AG |
119 | case JV_CONSTANT_Fieldref: |
120 | { | |
121 | _Jv_ushort class_index, name_and_type_index; | |
7941ceab | 122 | _Jv_loadIndexes (&pool->data[index], |
58eb6e7c AG |
123 | class_index, |
124 | name_and_type_index); | |
7941ceab | 125 | jclass owner = (_Jv_ResolvePoolEntry (klass, class_index)).clazz; |
58eb6e7c AG |
126 | |
127 | if (owner != klass) | |
128 | _Jv_InitClass (owner); | |
129 | ||
130 | _Jv_ushort name_index, type_index; | |
7941ceab | 131 | _Jv_loadIndexes (&pool->data[name_and_type_index], |
58eb6e7c AG |
132 | name_index, |
133 | type_index); | |
134 | ||
7941ceab AG |
135 | _Jv_Utf8Const *field_name = pool->data[name_index].utf8; |
136 | _Jv_Utf8Const *field_type_name = pool->data[type_index].utf8; | |
58eb6e7c AG |
137 | |
138 | // FIXME: The implementation of this function | |
139 | // (_Jv_FindClassFromSignature) will generate an instance of | |
140 | // _Jv_Utf8Const for each call if the field type is a class name | |
141 | // (Lxx.yy.Z;). This may be too expensive to do for each and | |
142 | // every fieldref being resolved. For now, we fix the problem by | |
143 | // only doing it when we have a loader different from the class | |
144 | // declaring the field. | |
145 | ||
146 | jclass field_type = 0; | |
147 | ||
148 | if (owner->loader != klass->loader) | |
149 | field_type = _Jv_FindClassFromSignature (field_type_name->data, | |
150 | klass->loader); | |
151 | ||
152 | _Jv_Field* the_field = 0; | |
153 | ||
154 | for (jclass cls = owner; cls != 0; cls = cls->getSuperclass ()) | |
155 | { | |
156 | for (int i = 0; i < cls->field_count; i++) | |
157 | { | |
158 | _Jv_Field *field = &cls->fields[i]; | |
159 | if (! _Jv_equalUtf8Consts (field->name, field_name)) | |
160 | continue; | |
161 | ||
162 | // now, check field access. | |
163 | ||
164 | if ( (cls == klass) | |
e409a2c8 TT |
165 | || ((field->flags & Modifier::PUBLIC) != 0) |
166 | || (((field->flags & Modifier::PROTECTED) != 0) | |
58eb6e7c | 167 | && cls->isAssignableFrom (klass)) |
e409a2c8 | 168 | || (((field->flags & Modifier::PRIVATE) == 0) |
58eb6e7c AG |
169 | && _Jv_ClassNameSamePackage (cls->name, |
170 | klass->name))) | |
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) | |
179 | JvThrow | |
180 | (new java::lang::LinkageError | |
181 | (JvNewStringLatin1 | |
182 | ("field type mismatch with different loaders"))); | |
183 | ||
184 | the_field = field; | |
185 | goto end_of_field_search; | |
186 | } | |
187 | else | |
188 | { | |
189 | JvThrow (new java::lang::IllegalAccessError); | |
190 | } | |
191 | } | |
192 | } | |
193 | ||
194 | end_of_field_search: | |
195 | if (the_field == 0) | |
196 | { | |
197 | jstring msg = JvNewStringLatin1 ("field "); | |
198 | msg = msg->concat (owner->getName ()); | |
199 | msg = msg->concat (JvNewStringLatin1(".")); | |
200 | msg = msg->concat (_Jv_NewStringUTF (field_name->data)); | |
201 | msg = msg->concat (JvNewStringLatin1(" was not found.")); | |
202 | throw_incompatible_class_change_error (msg); | |
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 AG |
229 | |
230 | int vtable_index = -1; | |
231 | _Jv_Method *the_method = 0; | |
232 | jclass found_class = 0; | |
233 | ||
ddf0fc6c BM |
234 | // First search the class itself. |
235 | the_method = _Jv_SearchMethodInClass (owner, klass, | |
236 | method_name, method_signature); | |
58eb6e7c | 237 | |
ddf0fc6c BM |
238 | if (the_method != 0) |
239 | { | |
240 | found_class = owner; | |
241 | goto end_of_method_search; | |
242 | } | |
58eb6e7c | 243 | |
ddf0fc6c BM |
244 | // If we are resolving an interface method, search the interface's |
245 | // superinterfaces (A superinterface is not an interface's superclass - | |
246 | // a superinterface is implemented by the interface). | |
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); | |
255 | ||
256 | for (int i=0; i < ifaces.count; i++) | |
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 | } | |
ddf0fc6c BM |
267 | |
268 | _Jv_Free (ifaces.list); | |
269 | ||
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, | |
279 | method_name, method_signature); | |
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 | ||
296 | if (pool->tags[index] == JV_CONSTANT_InterfaceMethodref) | |
297 | vtable_index = -1; | |
298 | else | |
299 | vtable_index = _Jv_DetermineVTableIndex | |
300 | (found_class, method_name, method_signature); | |
301 | ||
302 | if (vtable_index == 0) | |
303 | throw_incompatible_class_change_error | |
304 | (JvNewStringLatin1 ("method not found")); | |
305 | ||
58eb6e7c AG |
306 | if (the_method == 0) |
307 | { | |
308 | jstring msg = JvNewStringLatin1 ("method "); | |
309 | msg = msg->concat (owner->getName ()); | |
310 | msg = msg->concat (JvNewStringLatin1(".")); | |
311 | msg = msg->concat (_Jv_NewStringUTF (method_name->data)); | |
312 | msg = msg->concat (JvNewStringLatin1(" was not found.")); | |
ddf0fc6c | 313 | JvThrow(new java::lang::NoSuchMethodError (msg)); |
58eb6e7c AG |
314 | } |
315 | ||
7941ceab | 316 | pool->data[index].rmethod = |
58eb6e7c AG |
317 | _Jv_BuildResolvedMethod(the_method, |
318 | found_class, | |
e409a2c8 | 319 | (the_method->accflags & Modifier::STATIC) != 0, |
58eb6e7c AG |
320 | vtable_index); |
321 | pool->tags[index] |= JV_CONSTANT_ResolvedFlag; | |
322 | } | |
323 | break; | |
324 | ||
325 | } | |
326 | ||
327 | return pool->data[index]; | |
328 | } | |
329 | ||
ddf0fc6c BM |
330 | // Find a method declared in the cls that is referenced from klass and |
331 | // perform access checks. | |
332 | _Jv_Method * | |
333 | _Jv_SearchMethodInClass (jclass cls, jclass klass, | |
334 | _Jv_Utf8Const *method_name, | |
335 | _Jv_Utf8Const *method_signature) | |
336 | { | |
337 | using namespace java::lang::reflect; | |
338 | ||
339 | for (int i = 0; i < cls->method_count; i++) | |
340 | { | |
341 | _Jv_Method *method = &cls->methods[i]; | |
342 | if ( (!_Jv_equalUtf8Consts (method->name, | |
343 | method_name)) | |
344 | || (!_Jv_equalUtf8Consts (method->signature, | |
345 | method_signature))) | |
346 | continue; | |
347 | ||
348 | if (cls == klass | |
349 | || ((method->accflags & Modifier::PUBLIC) != 0) | |
350 | || (((method->accflags & Modifier::PROTECTED) != 0) | |
351 | && cls->isAssignableFrom (klass)) | |
352 | || (((method->accflags & Modifier::PRIVATE) == 0) | |
353 | && _Jv_ClassNameSamePackage (cls->name, | |
354 | klass->name))) | |
355 | { | |
356 | return method; | |
357 | } | |
358 | else | |
359 | { | |
360 | JvThrow (new java::lang::IllegalAccessError); | |
361 | } | |
362 | } | |
363 | return 0; | |
364 | } | |
eb4534a6 | 365 | |
58eb6e7c AG |
366 | void |
367 | _Jv_ResolveField (_Jv_Field *field, java::lang::ClassLoader *loader) | |
368 | { | |
369 | if (! field->isResolved ()) | |
370 | { | |
371 | _Jv_Utf8Const *sig = (_Jv_Utf8Const*)field->type; | |
372 | field->type = _Jv_FindClassFromSignature (sig->data, loader); | |
373 | field->flags &= ~_Jv_FIELD_UNRESOLVED_FLAG; | |
374 | } | |
375 | } | |
376 | ||
58eb6e7c AG |
377 | /** FIXME: this is a terribly inefficient algorithm! It would improve |
378 | things if compiled classes to know vtable offset, and _Jv_Method had | |
379 | a field for this. | |
380 | ||
381 | Returns 0 if this class does not declare the given method. | |
382 | Returns -1 if the given method does not appear in the vtable. | |
383 | i.e., it is static, private, final or a constructor. | |
384 | Otherwise, returns the vtable index. */ | |
385 | int | |
386 | _Jv_DetermineVTableIndex (jclass klass, | |
387 | _Jv_Utf8Const *name, | |
388 | _Jv_Utf8Const *signature) | |
389 | { | |
e409a2c8 TT |
390 | using namespace java::lang::reflect; |
391 | ||
58eb6e7c AG |
392 | jclass super_class = klass->getSuperclass (); |
393 | ||
394 | if (super_class != NULL) | |
395 | { | |
396 | int prev = _Jv_DetermineVTableIndex (super_class, | |
397 | name, | |
398 | signature); | |
399 | if (prev != 0) | |
400 | return prev; | |
401 | } | |
402 | ||
403 | /* at this point, we know that the super-class does not declare | |
404 | * the method. Otherwise, the above call would have found it, and | |
405 | * determined the result of this function (-1 or some positive | |
406 | * number). | |
407 | */ | |
408 | ||
409 | _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); | |
410 | ||
411 | /* now, if we do not declare this method, return zero */ | |
412 | if (meth == NULL) | |
413 | return 0; | |
414 | ||
415 | /* so now, we know not only that the super class does not declare the | |
416 | * method, but we do! So, this is a first declaration of the method. */ | |
417 | ||
418 | /* now, the checks for things that are declared in this class, but do | |
419 | * not go into the vtable. There are three cases. | |
420 | * 1) the method is static, private or final | |
421 | * 2) the class itself is final, or | |
422 | * 3) it is the method <init> | |
423 | */ | |
424 | ||
e409a2c8 TT |
425 | if ((meth->accflags & (Modifier::STATIC |
426 | | Modifier::PRIVATE | |
427 | | Modifier::FINAL)) != 0 | |
428 | || (klass->accflags & Modifier::FINAL) != 0 | |
58eb6e7c AG |
429 | || _Jv_equalUtf8Consts (name, init_name)) |
430 | return -1; | |
431 | ||
432 | /* reaching this point, we know for sure, that the method in question | |
433 | * will be in the vtable. The question is where. */ | |
434 | ||
435 | /* the base offset, is where we will start assigning vtable | |
436 | * indexes for this class. It is 1 for base classes | |
437 | * (vtable->method[0] is unused), and for non-base classes it is the | |
438 | * number of entries in the super class' vtable plus 1. */ | |
439 | ||
440 | int base_offset; | |
441 | if (super_class == 0) | |
442 | base_offset = 1; | |
443 | else | |
444 | base_offset = super_class->vtable_method_count+1; | |
445 | ||
446 | /* we will consider methods 0..this_method_index-1. And for each one, | |
447 | * determine if it is new (i.e., if it appears in the super class), | |
448 | * and if it should go in the vtable. If so, increment base_offset */ | |
449 | ||
450 | int this_method_index = meth - (&klass->methods[0]); | |
451 | ||
452 | for (int i = 0; i < this_method_index; i++) | |
453 | { | |
454 | _Jv_Method *m = &klass->methods[i]; | |
455 | ||
456 | /* fist some checks for things that surely do not go in the | |
457 | * vtable */ | |
458 | ||
e409a2c8 | 459 | if ((m->accflags & (Modifier::STATIC | Modifier::PRIVATE)) != 0) |
58eb6e7c AG |
460 | continue; |
461 | if (_Jv_equalUtf8Consts (m->name, init_name)) | |
462 | continue; | |
463 | ||
464 | /* Then, we need to know if this method appears in the | |
465 | superclass. (This is where this function gets expensive) */ | |
466 | _Jv_Method *sm = _Jv_LookupDeclaredMethod (super_class, | |
467 | m->name, | |
468 | m->signature); | |
469 | ||
470 | /* if it was somehow declared in the superclass, skip this */ | |
471 | if (sm != NULL) | |
472 | continue; | |
473 | ||
474 | /* but if it is final, and not declared in the super class, | |
475 | * then we also skip it */ | |
e409a2c8 | 476 | if ((m->accflags & Modifier::FINAL) != 0) |
58eb6e7c AG |
477 | continue; |
478 | ||
479 | /* finally, we can assign the index of this method */ | |
480 | /* m->vtable_index = base_offset */ | |
481 | base_offset += 1; | |
482 | } | |
483 | ||
484 | return base_offset; | |
485 | } | |
486 | ||
487 | /* this is installed in place of abstract methods */ | |
488 | static void | |
489 | _Jv_abstractMethodError () | |
490 | { | |
491 | JvThrow (new java::lang::AbstractMethodError); | |
492 | } | |
493 | ||
494 | void | |
495 | _Jv_PrepareClass(jclass klass) | |
496 | { | |
e409a2c8 TT |
497 | using namespace java::lang::reflect; |
498 | ||
58eb6e7c AG |
499 | /* |
500 | * The job of this function is to: 1) assign storage to fields, and 2) | |
501 | * build the vtable. static fields are assigned real memory, instance | |
502 | * fields are assigned offsets. | |
503 | * | |
504 | * NOTE: we have a contract with the garbage collector here. Static | |
505 | * reference fields must not be resolved, until after they have storage | |
506 | * assigned which is the check used by the collector to see if it | |
507 | * should indirect the static field reference and mark the object | |
508 | * pointed to. | |
509 | * | |
510 | * Most fields are resolved lazily (i.e. have their class-type | |
511 | * assigned) when they are accessed the first time by calling as part | |
512 | * of _Jv_ResolveField, which is allways called after _Jv_PrepareClass. | |
513 | * Static fields with initializers are resolved as part of this | |
514 | * function, as are fields with primitive types. | |
515 | */ | |
516 | ||
517 | if (! _Jv_IsInterpretedClass (klass)) | |
518 | return; | |
519 | ||
520 | if (klass->state >= JV_STATE_PREPARED) | |
521 | return; | |
522 | ||
523 | // make sure super-class is linked. This involves taking a lock on | |
524 | // the super class, so we use the Java method resolveClass, which will | |
525 | // unlock it properly, should an exception happen. | |
526 | ||
efc3b511 | 527 | java::lang::ClassLoader::resolveClass0 (klass->superclass); |
58eb6e7c AG |
528 | |
529 | _Jv_InterpClass *clz = (_Jv_InterpClass*)klass; | |
530 | ||
531 | /************ PART ONE: OBJECT LAYOUT ***************/ | |
532 | ||
533 | int instance_size; | |
534 | int static_size; | |
535 | ||
536 | // java.lang.Object is never interpreted! | |
537 | instance_size = clz->superclass->size (); | |
538 | static_size = 0; | |
539 | ||
540 | for (int i = 0; i < clz->field_count; i++) | |
541 | { | |
542 | int field_size; | |
543 | int field_align; | |
544 | ||
545 | _Jv_Field *field = &clz->fields[i]; | |
546 | ||
547 | if (! field->isRef ()) | |
548 | { | |
549 | // it's safe to resolve the field here, since it's | |
550 | // a primitive class, which does not cause loading to happen. | |
551 | _Jv_ResolveField (field, clz->loader); | |
552 | ||
553 | field_size = field->type->size (); | |
554 | field_align = get_alignment_from_class (field->type); | |
555 | } | |
556 | else | |
557 | { | |
558 | field_size = sizeof (jobject); | |
559 | field_align = __alignof__ (jobject); | |
560 | } | |
561 | ||
562 | #ifndef COMPACT_FIELDS | |
563 | field->bsize = field_size; | |
564 | #endif | |
565 | ||
e409a2c8 | 566 | if (field->flags & Modifier::STATIC) |
58eb6e7c AG |
567 | { |
568 | /* this computes an offset into a region we'll allocate | |
569 | shortly, and then add this offset to the start address */ | |
570 | ||
571 | static_size = ROUND (static_size, field_align); | |
572 | field->u.boffset = static_size; | |
573 | static_size += field_size; | |
574 | } | |
575 | else | |
576 | { | |
577 | instance_size = ROUND (instance_size, field_align); | |
578 | field->u.boffset = instance_size; | |
579 | instance_size += field_size; | |
580 | } | |
581 | } | |
582 | ||
583 | // set the instance size for the class | |
584 | clz->size_in_bytes = instance_size; | |
585 | ||
586 | // allocate static memory | |
587 | if (static_size != 0) | |
588 | { | |
589 | char *static_data = (char*)_Jv_AllocBytesChecked (static_size); | |
590 | ||
591 | memset (static_data, 0, static_size); | |
592 | ||
593 | for (int i = 0; i < clz->field_count; i++) | |
594 | { | |
595 | _Jv_Field *field = &clz->fields[i]; | |
596 | ||
e409a2c8 | 597 | if ((field->flags & Modifier::STATIC) != 0) |
58eb6e7c AG |
598 | { |
599 | field->u.addr = static_data + field->u.boffset; | |
600 | ||
601 | if (clz->field_initializers[i] != 0) | |
602 | { | |
603 | _Jv_ResolveField (field, clz->loader); | |
604 | _Jv_InitField (0, clz, i); | |
605 | } | |
606 | } | |
607 | } | |
608 | ||
609 | // now we don't need the field_initializers anymore, so let the | |
610 | // collector get rid of it! | |
611 | ||
612 | clz->field_initializers = 0; | |
613 | } | |
614 | ||
615 | /************ PART TWO: VTABLE LAYOUT ***************/ | |
616 | ||
617 | /* preparation: build the vtable stubs (even interfaces can) | |
618 | have code -- for static constructors. */ | |
619 | for (int i = 0; i < clz->method_count; i++) | |
620 | { | |
facc279f | 621 | _Jv_MethodBase *imeth = clz->interpreted_methods[i]; |
58eb6e7c | 622 | |
facc279f | 623 | if ((clz->methods[i].accflags & Modifier::NATIVE) != 0) |
58eb6e7c | 624 | { |
facc279f TT |
625 | // You might think we could use a virtual `ncode' method in |
626 | // the _Jv_MethodBase and unify the native and non-native | |
627 | // cases. Well, we can't, because we don't allocate these | |
628 | // objects using `new', and thus they don't get a vtable. | |
629 | _Jv_JNIMethod *jnim = reinterpret_cast<_Jv_JNIMethod *> (imeth); | |
630 | clz->methods[i].ncode = jnim->ncode (); | |
58eb6e7c | 631 | } |
facc279f | 632 | else if (imeth != 0) // it could be abstract |
58eb6e7c | 633 | { |
715bdd81 | 634 | _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (imeth); |
facc279f | 635 | clz->methods[i].ncode = im->ncode (); |
58eb6e7c AG |
636 | } |
637 | } | |
638 | ||
e409a2c8 | 639 | if (clz->accflags & Modifier::INTERFACE) |
58eb6e7c AG |
640 | { |
641 | clz->state = JV_STATE_PREPARED; | |
642 | clz->notifyAll (); | |
643 | return; | |
644 | } | |
645 | ||
58eb6e7c AG |
646 | /* Now onto the actual job: vtable layout. First, count how many new |
647 | methods we have */ | |
648 | int new_method_count = 0; | |
649 | ||
650 | jclass super_class = clz->getSuperclass (); | |
651 | ||
652 | if (super_class == 0) | |
653 | throw_internal_error ("cannot handle interpreted base classes"); | |
654 | ||
655 | for (int i = 0; i < clz->method_count; i++) | |
656 | { | |
657 | _Jv_Method *this_meth = &clz->methods[i]; | |
658 | ||
e409a2c8 | 659 | if ((this_meth->accflags & (Modifier::STATIC | Modifier::PRIVATE)) != 0 |
58eb6e7c AG |
660 | || _Jv_equalUtf8Consts (this_meth->name, init_name)) |
661 | { | |
662 | /* skip this, it doesn't go in the vtable */ | |
663 | continue; | |
664 | } | |
665 | ||
666 | _Jv_Method *orig_meth = _Jv_LookupDeclaredMethod (super_class, | |
667 | this_meth->name, | |
668 | this_meth->signature); | |
669 | ||
670 | if (orig_meth == 0) | |
671 | { | |
672 | // new methods that are final, also don't go in the vtable | |
e409a2c8 | 673 | if ((this_meth->accflags & Modifier::FINAL) != 0) |
58eb6e7c AG |
674 | continue; |
675 | ||
676 | new_method_count += 1; | |
677 | continue; | |
678 | } | |
679 | ||
e409a2c8 TT |
680 | if ((orig_meth->accflags & (Modifier::STATIC |
681 | | Modifier::PRIVATE | |
682 | | Modifier::FINAL)) != 0 | |
683 | || ((orig_meth->accflags & Modifier::ABSTRACT) == 0 | |
684 | && (this_meth->accflags & Modifier::ABSTRACT) != 0 | |
685 | && (klass->accflags & Modifier::ABSTRACT) == 0)) | |
58eb6e7c AG |
686 | { |
687 | clz->state = JV_STATE_ERROR; | |
688 | clz->notifyAll (); | |
689 | JvThrow (new java::lang::IncompatibleClassChangeError | |
690 | (clz->getName ())); | |
691 | } | |
692 | ||
693 | /* FIXME: At this point, if (loader != super_class->loader), we | |
694 | * need to "impose class loader constraints" for the types | |
695 | * involved in the signature of this method */ | |
696 | } | |
697 | ||
698 | /* determine size */ | |
699 | int vtable_count = (super_class->vtable_method_count) + new_method_count; | |
700 | clz->vtable_method_count = vtable_count; | |
701 | ||
702 | /* allocate vtable structure */ | |
703 | _Jv_VTable *vtable = (_Jv_VTable*) | |
704 | _Jv_AllocBytesChecked (sizeof (_Jv_VTable) | |
705 | + (sizeof (void*) * (vtable_count))); | |
706 | vtable->clas = clz; | |
707 | ||
715bdd81 AH |
708 | { |
709 | jclass effective_superclass = super_class; | |
710 | ||
711 | /* If super_class is abstract or an interface it has no vtable. | |
712 | We need to find a real one... */ | |
713 | while (effective_superclass && effective_superclass->vtable == NULL) | |
714 | effective_superclass = effective_superclass->superclass; | |
715 | ||
716 | /* copy super class' vtable entries (index 0 goes unused). */ | |
717 | if (effective_superclass && effective_superclass->vtable) | |
718 | memcpy ((void*)&vtable->method[1], | |
719 | (void*)&effective_superclass->vtable->method[1], | |
720 | sizeof (void*) * effective_superclass->vtable_method_count); | |
721 | } | |
58eb6e7c AG |
722 | |
723 | /* now, install our own vtable entries, reprise... */ | |
724 | for (int i = 0; i < clz->method_count; i++) | |
725 | { | |
726 | _Jv_Method *this_meth = &clz->methods[i]; | |
727 | ||
728 | int index = _Jv_DetermineVTableIndex (clz, | |
729 | this_meth->name, | |
730 | this_meth->signature); | |
731 | ||
732 | if (index == 0) | |
733 | throw_internal_error ("method now found in own class"); | |
734 | ||
735 | if (index != -1) | |
736 | { | |
737 | if (index > clz->vtable_method_count+1) | |
738 | throw_internal_error ("vtable problem..."); | |
739 | ||
740 | if (clz->interpreted_methods[i] == 0) | |
741 | vtable->method[index] = (void*)&_Jv_abstractMethodError; | |
742 | else | |
743 | vtable->method[index] = this_meth->ncode; | |
744 | } | |
745 | } | |
746 | ||
747 | /* finally, assign the vtable! */ | |
748 | clz->vtable = vtable; | |
749 | ||
750 | /* wooha! we're done. */ | |
751 | clz->state = JV_STATE_PREPARED; | |
752 | clz->notifyAll (); | |
753 | } | |
754 | ||
755 | /** Do static initialization for fields with a constant initializer */ | |
756 | void | |
757 | _Jv_InitField (jobject obj, jclass klass, int index) | |
758 | { | |
e409a2c8 TT |
759 | using namespace java::lang::reflect; |
760 | ||
58eb6e7c AG |
761 | if (obj != 0 && klass == 0) |
762 | klass = obj->getClass (); | |
763 | ||
764 | if (!_Jv_IsInterpretedClass (klass)) | |
765 | return; | |
766 | ||
767 | _Jv_InterpClass *clz = (_Jv_InterpClass*)klass; | |
768 | ||
769 | _Jv_Field * field = (&clz->fields[0]) + index; | |
770 | ||
771 | if (index > clz->field_count) | |
772 | throw_internal_error ("field out of range"); | |
773 | ||
774 | int init = clz->field_initializers[index]; | |
775 | if (init == 0) | |
776 | return; | |
777 | ||
778 | _Jv_Constants *pool = &clz->constants; | |
779 | int tag = pool->tags[init]; | |
780 | ||
781 | if (! field->isResolved ()) | |
782 | throw_internal_error ("initializing unresolved field"); | |
783 | ||
e409a2c8 | 784 | if (obj==0 && ((field->flags & Modifier::STATIC) == 0)) |
58eb6e7c AG |
785 | throw_internal_error ("initializing non-static field with no object"); |
786 | ||
787 | void *addr = 0; | |
788 | ||
e409a2c8 | 789 | if ((field->flags & Modifier::STATIC) != 0) |
58eb6e7c AG |
790 | addr = (void*) field->u.addr; |
791 | else | |
792 | addr = (void*) (((char*)obj) + field->u.boffset); | |
793 | ||
794 | switch (tag) | |
795 | { | |
796 | case JV_CONSTANT_String: | |
797 | { | |
798 | _Jv_MonitorEnter (clz); | |
799 | jstring str; | |
7941ceab AG |
800 | str = _Jv_NewStringUtf8Const (pool->data[init].utf8); |
801 | pool->data[init].string = str; | |
58eb6e7c AG |
802 | pool->tags[init] = JV_CONSTANT_ResolvedString; |
803 | _Jv_MonitorExit (clz); | |
804 | } | |
805 | /* fall through */ | |
806 | ||
807 | case JV_CONSTANT_ResolvedString: | |
808 | if (! (field->type == &StringClass || field->type == &ObjectClass)) | |
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 */ |