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 */
|
---|