Fix LDC, LDC_W, and INSTANCEOF opcodes, more debugging
[jamvm-avr32-jem.git] / src / resolve.c
bloba60d59dd334c53450630f59cc76af1d8b159712e
1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007
3 * Robert Lougher <rob@lougher.org.uk>.
5 * This file is part of JamVM.
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.
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.
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.
22 #include <stdio.h>
23 #include <string.h>
24 #include "jam.h"
26 MethodBlock *findMethod(Class *class, char *methodname, char *type) {
27 ClassBlock *cb = CLASS_CB(class);
28 MethodBlock *mb = cb->methods;
29 int i;
31 for(i = 0; i < cb->methods_count; i++,mb++)
32 if((strcmp(mb->name, methodname) == 0) && (strcmp(mb->type, type) == 0))
33 return mb;
35 return NULL;
38 /* As a Java program can't have two fields with the same name but different types,
39 we used to give up if we found a field with the right name but wrong type.
40 However, obfuscators rename fields, breaking this optimisation.
42 FieldBlock *findField(Class *class, char *fieldname, char *type) {
43 ClassBlock *cb = CLASS_CB(class);
44 FieldBlock *fb = cb->fields;
45 int i;
47 for(i = 0; i < cb->fields_count; i++,fb++)
48 if(strcmp(fb->name, fieldname) == 0 && (strcmp(fb->type, type) == 0))
49 return fb;
51 return NULL;
54 MethodBlock *lookupMethod(Class *class, char *methodname, char *type) {
55 MethodBlock *mb;
57 if((mb = findMethod(class, methodname, type)))
58 return mb;
60 if(CLASS_CB(class)->super)
61 return lookupMethod(CLASS_CB(class)->super, methodname, type);
63 return NULL;
66 FieldBlock *lookupField(Class *class, char *fieldname, char *fieldtype) {
67 ClassBlock *cb;
68 FieldBlock *fb;
69 int i;
71 if((fb = findField(class, fieldname, fieldtype)) != NULL)
72 return fb;
74 cb = CLASS_CB(class);
75 i = cb->super ? CLASS_CB(cb->super)->imethod_table_size : 0;
77 for(; i < cb->imethod_table_size; i++) {
78 Class *intf = cb->imethod_table[i].interface;
79 if((fb = findField(intf, fieldname, fieldtype)) != NULL)
80 return fb;
83 if(cb->super)
84 return lookupField(cb->super, fieldname, fieldtype);
86 return NULL;
89 Class *resolveClass(Class *class, int cp_index, int init) {
90 ConstantPool *cp = &(CLASS_CB(class)->constant_pool);
91 Class *resolved_class = NULL;
93 retry:
94 switch(CP_TYPE(cp, cp_index)) {
95 case CONSTANT_Locked:
96 goto retry;
98 case CONSTANT_ResolvedClass:
99 resolved_class = (Class *)CP_INFO(cp, cp_index);
100 break;
102 case CONSTANT_Class: {
103 char *classname;
104 int name_idx = CP_CLASS(cp, cp_index);
106 if(CP_TYPE(cp, cp_index) != CONSTANT_Class)
107 goto retry;
109 classname = CP_UTF8(cp, name_idx);
110 resolved_class = findClassFromClass(classname, class);
112 /* If we can't find the class an exception will already have
113 been thrown */
115 if(resolved_class == NULL)
116 return NULL;
118 if(!checkClassAccess(resolved_class, class)) {
119 signalException("java/lang/IllegalAccessException", "class is not accessible");
120 return NULL;
123 CP_TYPE(cp, cp_index) = CONSTANT_Locked;
124 MBARRIER();
125 CP_INFO(cp, cp_index) = (uintptr_t)resolved_class;
126 MBARRIER();
127 CP_TYPE(cp, cp_index) = CONSTANT_ResolvedClass;
129 break;
133 if(init)
134 initClass(resolved_class);
136 return resolved_class;
139 MethodBlock *resolveMethod(Class *class, int cp_index) {
140 ConstantPool *cp = &(CLASS_CB(class)->constant_pool);
141 MethodBlock *mb = NULL;
143 retry:
144 switch(CP_TYPE(cp, cp_index)) {
145 case CONSTANT_Locked:
146 goto retry;
148 case CONSTANT_Resolved:
149 mb = (MethodBlock *)CP_INFO(cp, cp_index);
150 break;
152 case CONSTANT_Methodref: {
153 Class *resolved_class;
154 ClassBlock *resolved_cb;
155 char *methodname, *methodtype;
156 int cl_idx = CP_METHOD_CLASS(cp, cp_index);
157 int name_type_idx = CP_METHOD_NAME_TYPE(cp, cp_index);
159 if(CP_TYPE(cp, cp_index) != CONSTANT_Methodref)
160 goto retry;
162 methodname = CP_UTF8(cp, CP_NAME_TYPE_NAME(cp, name_type_idx));
164 methodtype = CP_UTF8(cp, CP_NAME_TYPE_TYPE(cp, name_type_idx));
165 resolved_class = resolveClass(class, cl_idx, FALSE);
166 resolved_cb = CLASS_CB(resolved_class);
168 if(exceptionOccurred())
169 return NULL;
171 if(resolved_cb->access_flags & ACC_INTERFACE) {
172 signalException("java/lang/IncompatibleClassChangeError", NULL);
173 return NULL;
176 mb = lookupMethod(resolved_class, methodname, methodtype);
178 if(mb) {
179 if((mb->access_flags & ACC_ABSTRACT) &&
180 !(resolved_cb->access_flags & ACC_ABSTRACT)) {
181 signalException("java/lang/AbstractMethodError", methodname);
182 return NULL;
185 if(!checkMethodAccess(mb, class)) {
186 signalException("java/lang/IllegalAccessException", "method is not accessible");
187 return NULL;
190 initClass(mb->class);
192 CP_TYPE(cp, cp_index) = CONSTANT_Locked;
193 MBARRIER();
194 CP_INFO(cp, cp_index) = (uintptr_t)mb;
195 MBARRIER();
196 CP_TYPE(cp, cp_index) = CONSTANT_Resolved;
197 } else
198 signalException("java/lang/NoSuchMethodError", methodname);
200 break;
204 return mb;
207 MethodBlock *resolveInterfaceMethod(Class *class, int cp_index) {
208 ConstantPool *cp = &(CLASS_CB(class)->constant_pool);
209 MethodBlock *mb = NULL;
211 retry:
212 switch(CP_TYPE(cp, cp_index)) {
213 case CONSTANT_Locked:
214 goto retry;
216 case CONSTANT_Resolved:
217 mb = (MethodBlock *)CP_INFO(cp, cp_index);
218 break;
220 case CONSTANT_InterfaceMethodref: {
221 Class *resolved_class;
222 char *methodname, *methodtype;
223 int cl_idx = CP_METHOD_CLASS(cp, cp_index);
224 int name_type_idx = CP_METHOD_NAME_TYPE(cp, cp_index);
226 if(CP_TYPE(cp, cp_index) != CONSTANT_InterfaceMethodref)
227 goto retry;
229 methodname = CP_UTF8(cp, CP_NAME_TYPE_NAME(cp, name_type_idx));
230 methodtype = CP_UTF8(cp, CP_NAME_TYPE_TYPE(cp, name_type_idx));
231 resolved_class = resolveClass(class, cl_idx, FALSE);
233 if(exceptionOccurred())
234 return NULL;
236 if(!(CLASS_CB(resolved_class)->access_flags & ACC_INTERFACE)) {
237 signalException("java/lang/IncompatibleClassChangeError", NULL);
238 return NULL;
241 if((mb = lookupMethod(resolved_class, methodname, methodtype)) == NULL) {
242 ClassBlock *cb = CLASS_CB(resolved_class);
243 int i;
245 for(i = 0; mb == NULL && (i < cb->imethod_table_size); i++) {
246 Class *intf = cb->imethod_table[i].interface;
247 mb = findMethod(intf, methodname, methodtype);
251 if(mb) {
252 CP_TYPE(cp, cp_index) = CONSTANT_Locked;
253 MBARRIER();
254 CP_INFO(cp, cp_index) = (uintptr_t)mb;
255 MBARRIER();
256 CP_TYPE(cp, cp_index) = CONSTANT_Resolved;
257 } else
258 signalException("java/lang/NoSuchMethodError", methodname);
260 break;
264 return mb;
267 FieldBlock *resolveField(Class *class, int cp_index) {
268 ConstantPool *cp = &(CLASS_CB(class)->constant_pool);
269 FieldBlock *fb = NULL;
271 retry:
272 switch(CP_TYPE(cp, cp_index)) {
273 case CONSTANT_Locked:
274 goto retry;
276 case CONSTANT_Resolved:
277 fb = (FieldBlock *)CP_INFO(cp, cp_index);
278 break;
280 case CONSTANT_Fieldref: {
281 Class *resolved_class;
282 char *fieldname, *fieldtype;
283 int cl_idx = CP_FIELD_CLASS(cp, cp_index);
284 int name_type_idx = CP_FIELD_NAME_TYPE(cp, cp_index);
286 if(CP_TYPE(cp, cp_index) != CONSTANT_Fieldref)
287 goto retry;
289 fieldname = CP_UTF8(cp, CP_NAME_TYPE_NAME(cp, name_type_idx));
290 fieldtype = CP_UTF8(cp, CP_NAME_TYPE_TYPE(cp, name_type_idx));
291 resolved_class = resolveClass(class, cl_idx, FALSE);
293 if(exceptionOccurred())
294 return NULL;
296 fb = lookupField(resolved_class, fieldname, fieldtype);
298 if(fb) {
299 if(!checkFieldAccess(fb, class)) {
300 signalException("java/lang/IllegalAccessException", "field is not accessible");
301 return NULL;
304 initClass(fb->class);
306 CP_TYPE(cp, cp_index) = CONSTANT_Locked;
307 MBARRIER();
308 CP_INFO(cp, cp_index) = (uintptr_t)fb;
309 MBARRIER();
310 CP_TYPE(cp, cp_index) = CONSTANT_Resolved;
311 } else
312 signalException("java/lang/NoSuchFieldError", fieldname);
314 break;
318 return fb;
321 uintptr_t resolveSingleConstant(Class *class, int cp_index) {
322 ConstantPool *cp = &(CLASS_CB(class)->constant_pool);
324 retry:
325 switch(CP_TYPE(cp, cp_index)) {
326 case CONSTANT_Locked:
327 goto retry;
329 case CONSTANT_Class:
330 resolveClass(class, cp_index, FALSE);
331 break;
333 case CONSTANT_String: {
334 Object *string;
335 int idx = CP_STRING(cp, cp_index);
337 if(CP_TYPE(cp, cp_index) != CONSTANT_String)
338 goto retry;
340 string = createString(CP_UTF8(cp, idx));
342 if(string) {
343 CP_TYPE(cp, cp_index) = CONSTANT_Locked;
344 MBARRIER();
345 CP_INFO(cp, cp_index) = (uintptr_t)findInternedString(string);
346 MBARRIER();
347 CP_TYPE(cp, cp_index) = CONSTANT_ResolvedString;
350 break;
353 default:
354 break;
357 return CP_INFO(cp, cp_index);
360 MethodBlock *lookupVirtualMethod(Object *ob, MethodBlock *mb) {
361 ClassBlock *cb = CLASS_CB(ob->class);
362 int mtbl_idx = mb->method_table_index;
364 if(mb->access_flags & ACC_PRIVATE)
365 return mb;
367 if(CLASS_CB(mb->class)->access_flags & ACC_INTERFACE) {
368 int i;
370 for(i = 0; (i < cb->imethod_table_size) &&
371 (mb->class != cb->imethod_table[i].interface); i++);
373 if(i == cb->imethod_table_size) {
374 signalException("java/lang/IncompatibleClassChangeError",
375 "unimplemented interface");
376 return NULL;
378 mtbl_idx = cb->imethod_table[i].offsets[mtbl_idx];
381 mb = cb->method_table[mtbl_idx];
383 if(mb->access_flags & ACC_ABSTRACT) {
384 signalException("java/lang/AbstractMethodError", mb->name);
385 return NULL;
388 return mb;
391 /* This function is used when rewriting a field access bytecode
392 in the direct-threaded interpreter. We need to know how many
393 slots are used on the stack, but the field reference may not
394 be resolved, and resolving at preparation will break Java's
395 lazy resolution semantics. */
397 #ifdef DIRECT
398 int peekIsFieldLong(Class *class, int cp_index) {
399 ConstantPool *cp = &(CLASS_CB(class)->constant_pool);
400 char *type = NULL;
402 retry:
403 switch(CP_TYPE(cp, cp_index)) {
404 case CONSTANT_Locked:
405 goto retry;
407 case CONSTANT_Resolved:
408 type = ((FieldBlock *)CP_INFO(cp, cp_index))->type;
409 break;
411 case CONSTANT_Fieldref: {
412 int name_type_idx = CP_FIELD_NAME_TYPE(cp, cp_index);
414 if(CP_TYPE(cp, cp_index) != CONSTANT_Fieldref)
415 goto retry;
417 type = CP_UTF8(cp, CP_NAME_TYPE_TYPE(cp, name_type_idx));
418 break;
422 return *type == 'J' || *type == 'D';
424 #endif