jamvm
view src/resolve.c @ 402:24373fc1d951
Add additional tracing support.
2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>
* .hgignore: Updated with autogen.sh output.
* configure.ac: Add new trace options.
* src/class.c,
* src/excep.c,
* src/natives.c,
* src/resolve.c: Add trace support.
* src/jam.h,
* src/dll.c,
* src/os/linux/os.c: Add support for reporting
the linking error using dlerror.
2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>
* .hgignore: Updated with autogen.sh output.
* configure.ac: Add new trace options.
* src/class.c,
* src/excep.c,
* src/natives.c,
* src/resolve.c: Add trace support.
* src/jam.h,
* src/dll.c,
* src/os/linux/os.c: Add support for reporting
the linking error using dlerror.
| author | andrew |
|---|---|
| date | Tue Aug 05 05:46:09 2008 +0100 (2008-08-05) |
| parents | 6131bd7f229c |
| children |
line source
1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
3 * Robert Lougher <rob@lougher.org.uk>.
4 *
5 * This file is part of JamVM.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
22 #include <stdio.h>
23 #include <string.h>
24 #include "jam.h"
25 #include "symbol.h"
26 #include "excep.h"
28 #ifdef TRACERESOLVE
29 #define TRACE(fmt, ...) jam_printf(fmt, ## __VA_ARGS__)
30 #define TRACE(fmt, ...)
31 #endif
33 MethodBlock *findMethod(Class *class, char *methodname, char *type) {
34 ClassBlock *cb = CLASS_CB(class);
35 MethodBlock *mb = cb->methods;
36 int i;
38 TRACE("<RESOLVE: Searching for method: %s with type: %s in class %s>\n", methodname, type, cb->name);
39 for(i = 0; i < cb->methods_count; i++,mb++) {
40 TRACE("<RESOLVE: Checking method: %s with type: %s>\n", mb->name, mb->type);
41 if(mb->name == methodname && mb->type == type)
42 return mb;
43 }
44 return NULL;
45 }
47 /* As a Java program can't have two fields with the same name but different types,
48 we used to give up if we found a field with the right name but wrong type.
49 However, obfuscators rename fields, breaking this optimisation.
50 */
51 FieldBlock *findField(Class *class, char *fieldname, char *type) {
52 ClassBlock *cb = CLASS_CB(class);
53 FieldBlock *fb = cb->fields;
54 int i;
56 for(i = 0; i < cb->fields_count; i++,fb++)
57 if(fb->name == fieldname && fb->type == type)
58 return fb;
60 return NULL;
61 }
63 MethodBlock *lookupMethod(Class *class, char *methodname, char *type) {
64 MethodBlock *mb;
66 if((mb = findMethod(class, methodname, type)))
67 return mb;
69 if(CLASS_CB(class)->super)
70 return lookupMethod(CLASS_CB(class)->super, methodname, type);
72 return NULL;
73 }
75 FieldBlock *lookupField(Class *class, char *fieldname, char *fieldtype) {
76 ClassBlock *cb;
77 FieldBlock *fb;
78 int i;
80 if((fb = findField(class, fieldname, fieldtype)) != NULL)
81 return fb;
83 cb = CLASS_CB(class);
84 i = cb->super ? CLASS_CB(cb->super)->imethod_table_size : 0;
86 for(; i < cb->imethod_table_size; i++) {
87 Class *intf = cb->imethod_table[i].interface;
88 if((fb = findField(intf, fieldname, fieldtype)) != NULL)
89 return fb;
90 }
92 if(cb->super)
93 return lookupField(cb->super, fieldname, fieldtype);
95 return NULL;
96 }
98 Class *resolveClass(Class *class, int cp_index, int init) {
99 ConstantPool *cp = &(CLASS_CB(class)->constant_pool);
100 Class *resolved_class = NULL;
102 retry:
103 switch(CP_TYPE(cp, cp_index)) {
104 case CONSTANT_Locked:
105 goto retry;
107 case CONSTANT_ResolvedClass:
108 resolved_class = (Class *)CP_INFO(cp, cp_index);
109 break;
111 case CONSTANT_Class: {
112 char *classname;
113 int name_idx = CP_CLASS(cp, cp_index);
115 if(CP_TYPE(cp, cp_index) != CONSTANT_Class)
116 goto retry;
118 classname = CP_UTF8(cp, name_idx);
119 resolved_class = findClassFromClass(classname, class);
121 /* If we can't find the class an exception will already have
122 been thrown */
124 if(resolved_class == NULL)
125 return NULL;
127 if(!checkClassAccess(resolved_class, class)) {
128 signalException(java_lang_IllegalAccessError, "class is not accessible");
129 return NULL;
130 }
132 CP_TYPE(cp, cp_index) = CONSTANT_Locked;
133 MBARRIER();
134 CP_INFO(cp, cp_index) = (uintptr_t)resolved_class;
135 MBARRIER();
136 CP_TYPE(cp, cp_index) = CONSTANT_ResolvedClass;
138 break;
139 }
140 }
142 if(init)
143 initClass(resolved_class);
145 return resolved_class;
146 }
148 MethodBlock *resolveMethod(Class *class, int cp_index) {
149 ConstantPool *cp = &(CLASS_CB(class)->constant_pool);
150 MethodBlock *mb = NULL;
152 retry:
153 switch(CP_TYPE(cp, cp_index)) {
154 case CONSTANT_Locked:
155 goto retry;
157 case CONSTANT_Resolved:
158 mb = (MethodBlock *)CP_INFO(cp, cp_index);
159 break;
161 case CONSTANT_Methodref: {
162 Class *resolved_class;
163 ClassBlock *resolved_cb;
164 char *methodname, *methodtype;
165 int cl_idx = CP_METHOD_CLASS(cp, cp_index);
166 int name_type_idx = CP_METHOD_NAME_TYPE(cp, cp_index);
168 if(CP_TYPE(cp, cp_index) != CONSTANT_Methodref)
169 goto retry;
171 methodname = CP_UTF8(cp, CP_NAME_TYPE_NAME(cp, name_type_idx));
173 methodtype = CP_UTF8(cp, CP_NAME_TYPE_TYPE(cp, name_type_idx));
174 resolved_class = resolveClass(class, cl_idx, FALSE);
175 resolved_cb = CLASS_CB(resolved_class);
177 if(exceptionOccurred())
178 return NULL;
180 if(resolved_cb->access_flags & ACC_INTERFACE) {
181 signalException(java_lang_IncompatibleClassChangeError, NULL);
182 return NULL;
183 }
185 mb = lookupMethod(resolved_class, methodname, methodtype);
187 if(mb) {
188 if((mb->access_flags & ACC_ABSTRACT) &&
189 !(resolved_cb->access_flags & ACC_ABSTRACT)) {
190 signalException(java_lang_AbstractMethodError, methodname);
191 return NULL;
192 }
194 if(!checkMethodAccess(mb, class)) {
195 signalException(java_lang_IllegalAccessError, "method is not accessible");
196 return NULL;
197 }
199 if(initClass(mb->class) == NULL)
200 return NULL;
202 CP_TYPE(cp, cp_index) = CONSTANT_Locked;
203 MBARRIER();
204 CP_INFO(cp, cp_index) = (uintptr_t)mb;
205 MBARRIER();
206 CP_TYPE(cp, cp_index) = CONSTANT_Resolved;
207 } else
208 signalException(java_lang_NoSuchMethodError, methodname);
210 break;
211 }
212 }
214 return mb;
215 }
217 MethodBlock *resolveInterfaceMethod(Class *class, int cp_index) {
218 ConstantPool *cp = &(CLASS_CB(class)->constant_pool);
219 MethodBlock *mb = NULL;
221 retry:
222 switch(CP_TYPE(cp, cp_index)) {
223 case CONSTANT_Locked:
224 goto retry;
226 case CONSTANT_Resolved:
227 mb = (MethodBlock *)CP_INFO(cp, cp_index);
228 break;
230 case CONSTANT_InterfaceMethodref: {
231 Class *resolved_class;
232 char *methodname, *methodtype;
233 int cl_idx = CP_METHOD_CLASS(cp, cp_index);
234 int name_type_idx = CP_METHOD_NAME_TYPE(cp, cp_index);
236 if(CP_TYPE(cp, cp_index) != CONSTANT_InterfaceMethodref)
237 goto retry;
239 methodname = CP_UTF8(cp, CP_NAME_TYPE_NAME(cp, name_type_idx));
240 methodtype = CP_UTF8(cp, CP_NAME_TYPE_TYPE(cp, name_type_idx));
241 resolved_class = resolveClass(class, cl_idx, FALSE);
243 if(exceptionOccurred())
244 return NULL;
246 if(!(CLASS_CB(resolved_class)->access_flags & ACC_INTERFACE)) {
247 signalException(java_lang_IncompatibleClassChangeError, NULL);
248 return NULL;
249 }
251 mb = lookupMethod(resolved_class, methodname, methodtype);
252 if(mb == NULL) {
253 ClassBlock *cb = CLASS_CB(resolved_class);
254 int i;
256 for(i = 0; mb == NULL && (i < cb->imethod_table_size); i++) {
257 Class *intf = cb->imethod_table[i].interface;
258 mb = findMethod(intf, methodname, methodtype);
259 }
260 }
262 if(mb) {
263 CP_TYPE(cp, cp_index) = CONSTANT_Locked;
264 MBARRIER();
265 CP_INFO(cp, cp_index) = (uintptr_t)mb;
266 MBARRIER();
267 CP_TYPE(cp, cp_index) = CONSTANT_Resolved;
268 } else
269 signalException(java_lang_NoSuchMethodError, methodname);
271 break;
272 }
273 }
275 return mb;
276 }
278 FieldBlock *resolveField(Class *class, int cp_index) {
279 ConstantPool *cp = &(CLASS_CB(class)->constant_pool);
280 FieldBlock *fb = NULL;
282 retry:
283 switch(CP_TYPE(cp, cp_index)) {
284 case CONSTANT_Locked:
285 goto retry;
287 case CONSTANT_Resolved:
288 fb = (FieldBlock *)CP_INFO(cp, cp_index);
289 break;
291 case CONSTANT_Fieldref: {
292 Class *resolved_class;
293 char *fieldname, *fieldtype;
294 int cl_idx = CP_FIELD_CLASS(cp, cp_index);
295 int name_type_idx = CP_FIELD_NAME_TYPE(cp, cp_index);
297 if(CP_TYPE(cp, cp_index) != CONSTANT_Fieldref)
298 goto retry;
300 fieldname = CP_UTF8(cp, CP_NAME_TYPE_NAME(cp, name_type_idx));
301 fieldtype = CP_UTF8(cp, CP_NAME_TYPE_TYPE(cp, name_type_idx));
302 resolved_class = resolveClass(class, cl_idx, FALSE);
304 if(exceptionOccurred())
305 return NULL;
307 fb = lookupField(resolved_class, fieldname, fieldtype);
309 if(fb) {
310 if(!checkFieldAccess(fb, class)) {
311 signalException(java_lang_IllegalAccessError, "field is not accessible");
312 return NULL;
313 }
315 if(initClass(fb->class) == NULL)
316 return NULL;
318 CP_TYPE(cp, cp_index) = CONSTANT_Locked;
319 MBARRIER();
320 CP_INFO(cp, cp_index) = (uintptr_t)fb;
321 MBARRIER();
322 CP_TYPE(cp, cp_index) = CONSTANT_Resolved;
323 } else
324 signalException(java_lang_NoSuchFieldError, fieldname);
326 break;
327 }
328 }
330 return fb;
331 }
333 uintptr_t resolveSingleConstant(Class *class, int cp_index) {
334 ConstantPool *cp = &(CLASS_CB(class)->constant_pool);
336 retry:
337 switch(CP_TYPE(cp, cp_index)) {
338 case CONSTANT_Locked:
339 goto retry;
341 case CONSTANT_Class:
342 resolveClass(class, cp_index, FALSE);
343 break;
345 case CONSTANT_String: {
346 Object *string;
347 int idx = CP_STRING(cp, cp_index);
349 if(CP_TYPE(cp, cp_index) != CONSTANT_String)
350 goto retry;
352 string = createString(CP_UTF8(cp, idx));
354 if(string) {
355 CP_TYPE(cp, cp_index) = CONSTANT_Locked;
356 MBARRIER();
357 CP_INFO(cp, cp_index) = (uintptr_t)findInternedString(string);
358 MBARRIER();
359 CP_TYPE(cp, cp_index) = CONSTANT_ResolvedString;
360 }
362 break;
363 }
365 default:
366 break;
367 }
369 return CP_INFO(cp, cp_index);
370 }
372 MethodBlock *lookupVirtualMethod(Object *ob, MethodBlock *mb) {
373 ClassBlock *cb = CLASS_CB(ob->class);
374 int mtbl_idx = mb->method_table_index;
376 if(mb->access_flags & ACC_PRIVATE)
377 return mb;
379 if(CLASS_CB(mb->class)->access_flags & ACC_INTERFACE) {
380 int i;
382 for(i = 0; (i < cb->imethod_table_size) &&
383 (mb->class != cb->imethod_table[i].interface); i++);
385 if(i == cb->imethod_table_size) {
386 signalException(java_lang_IncompatibleClassChangeError,
387 "unimplemented interface");
388 return NULL;
389 }
390 mtbl_idx = cb->imethod_table[i].offsets[mtbl_idx];
391 }
393 mb = cb->method_table[mtbl_idx];
395 if(mb->access_flags & ACC_ABSTRACT) {
396 signalException(java_lang_AbstractMethodError, mb->name);
397 return NULL;
398 }
400 return mb;
401 }
403 /* This function is used when rewriting a field access bytecode
404 in the direct-threaded interpreter. We need to know how many
405 slots are used on the stack, but the field reference may not
406 be resolved, and resolving at preparation will break Java's
407 lazy resolution semantics. */
409 #ifdef DIRECT
410 int peekIsFieldLong(Class *class, int cp_index) {
411 ConstantPool *cp = &(CLASS_CB(class)->constant_pool);
412 char *type = NULL;
414 retry:
415 switch(CP_TYPE(cp, cp_index)) {
416 case CONSTANT_Locked:
417 goto retry;
419 case CONSTANT_Resolved:
420 type = ((FieldBlock *)CP_INFO(cp, cp_index))->type;
421 break;
423 case CONSTANT_Fieldref: {
424 int name_type_idx = CP_FIELD_NAME_TYPE(cp, cp_index);
426 if(CP_TYPE(cp, cp_index) != CONSTANT_Fieldref)
427 goto retry;
429 type = CP_UTF8(cp, CP_NAME_TYPE_TYPE(cp, name_type_idx));
430 break;
431 }
432 }
434 return *type == 'J' || *type == 'D';
435 }
436 #endif
