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