ecbb6e916f667197ac3a791332e1021011197372
[cacao.git] / src / vm / stackmap.c
1 /* src/vm/stackmap.c - class attribute StackMapTable
2
3    Copyright (C) 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27 #include "vm/types.h"
28
29 #include "mm/memory.h"
30
31 #include "vm/class.hpp"
32 #include "vm/exceptions.hpp"
33 #include "vm/method.h"
34 #include "vm/options.h"
35 #include "vm/stackmap.h"
36 #include "vm/statistics.h"
37 #include "vm/suck.hpp"
38
39
40 /* stackmap_get_verification_type_info *****************************************
41
42    union verification_type_info {
43        Top_variable_info;
44            Integer_variable_info;
45            Float_variable_info;
46            Long_variable_info;
47            Double_variable_info;
48            Null_variable_info;
49            UninitializedThis_variable_info;
50            Object_variable_info;
51            Uninitialized_variable_info;
52    }
53
54    Top_variable_info {
55        u1 tag = ITEM_Top;  // 0
56    }
57
58    Integer_variable_info {
59        u1 tag = ITEM_Integer;  // 1
60    }
61
62    Float_variable_info {
63        u1 tag = ITEM_Float;  // 2
64    }
65
66    Long_variable_info {
67        u1 tag = ITEM_Long;  // 4
68    }
69
70    Double_variable_info {
71        u1 tag = ITEM_Double;  // 3
72    }
73
74    Null_variable_info {
75        u1 tag = ITEM_Null;  // 5
76    }
77
78    UninitializedThis_variable_info {
79        u1 tag = ITEM_UninitializedThis;  // 6
80    }
81
82    Object_variable_info {
83        u1 tag = ITEM_Object;  // 7
84            u2 cpool_index;
85    }
86
87    Uninitialized_variable_info {
88        u1 tag = ITEM_Uninitialized;  // 8
89            u2 offset;
90    }
91
92 *******************************************************************************/
93
94 static bool stackmap_get_verification_type_info(classbuffer *cb, verification_type_info_t *verification_type_info)
95 {
96         /* get verification type */
97
98         if (!suck_check_classbuffer_size(cb, 1))
99                 return false;
100
101         verification_type_info->tag = suck_u1(cb);
102
103         /* process the tag */
104
105         switch (verification_type_info->tag) {
106         case ITEM_Top:
107         case ITEM_Integer:
108         case ITEM_Float:
109         case ITEM_Long:
110         case ITEM_Double:
111         case ITEM_Null:
112         case ITEM_UninitializedThis:
113                 break;
114
115         case ITEM_Object:
116                 /* get constant pool index */
117
118                 if (!suck_check_classbuffer_size(cb, 2))
119                         return false;
120
121                 verification_type_info->Object_variable_info.cpool_index = suck_u2(cb);
122                 break;
123
124         case ITEM_Uninitialized:
125                 /* get offset */
126
127                 if (!suck_check_classbuffer_size(cb, 2))
128                         return false;
129
130                 verification_type_info->Uninitialized_variable_info.offset = suck_u2(cb);
131                 break;
132         }
133
134         return true;
135 }
136
137
138 /* stackmap_get_same_locals_1_stack_item_frame *********************************
139
140    same_locals_1_stack_item_frame {
141        u1 frame_type = SAME_LOCALS_1_STACK_ITEM;  // 64-127
142            verification_type_info stack[1];
143    }
144
145 *******************************************************************************/
146
147 static bool stackmap_get_same_locals_1_stack_item_frame(classbuffer *cb, stack_map_frame_t *stack_map_frame)
148 {
149         same_locals_1_stack_item_frame_t *same_locals_1_stack_item_frame;
150
151         /* for convenience */
152
153         same_locals_1_stack_item_frame =
154                 &(stack_map_frame->same_locals_1_stack_item_frame);
155
156         if (!stackmap_get_verification_type_info(cb, &(same_locals_1_stack_item_frame->stack[0])))
157                 return false;
158
159         return true;
160 }
161
162
163 /* stackmap_get_same_locals_1_stack_item_frame_extended ************************
164
165    same_locals_1_stack_item_frame_extended {
166        u1 frame_type = SAME_LOCALS_1_STACK_ITEM_EXTENDED;  // 247
167            u2 offset_delta;
168            verification_type_info stack[1];
169    }
170
171 *******************************************************************************/
172
173 static bool stackmap_get_same_locals_1_stack_item_frame_extended(classbuffer *cb, stack_map_frame_t *stack_map_frame)
174 {
175         same_locals_1_stack_item_frame_extended_t *same_locals_1_stack_item_frame_extended;
176
177         /* for convenience */
178
179         same_locals_1_stack_item_frame_extended =
180                 &(stack_map_frame->same_locals_1_stack_item_frame_extended);
181
182         /* check buffer size */
183
184         if (!suck_check_classbuffer_size(cb, 2))
185                 return false;
186
187         /* get offset delta */
188
189         same_locals_1_stack_item_frame_extended->offset_delta = suck_u2(cb);
190
191         /* process stack */
192
193         if (!stackmap_get_verification_type_info(cb, &(same_locals_1_stack_item_frame_extended->stack[0])))
194                 return false;
195
196         return true;
197 }
198
199
200 /* stackmap_get_chop_frame *****************************************************
201
202    chop_frame {
203        u1 frame_type = CHOP_FRAME;  // 248-250
204            u2 offset_delta;
205    }
206
207 *******************************************************************************/
208
209 static bool stackmap_get_chop_frame(classbuffer *cb,
210                                                                         stack_map_frame_t *stack_map_frame)
211 {
212         chop_frame_t *chop_frame;
213
214         /* for convenience */
215
216         chop_frame = &(stack_map_frame->chop_frame);
217
218         /* check buffer size */
219
220         if (!suck_check_classbuffer_size(cb, 2))
221                 return false;
222
223         /* get offset delta */
224
225         chop_frame->offset_delta = suck_u2(cb);
226
227         return true;
228 }
229
230
231 /* stackmap_get_same_frame_extended ********************************************
232
233    same_frame_extended {
234        u1 frame_type = SAME_FRAME_EXTENDED;  // 251
235            u2 offset_delta;
236    }
237
238 *******************************************************************************/
239
240 static bool stackmap_get_same_frame_extended(classbuffer *cb,
241                                                                                          stack_map_frame_t *stack_map_frame)
242 {
243         same_frame_extended_t *same_frame_extended;
244
245         /* for convenience */
246
247         same_frame_extended = &(stack_map_frame->same_frame_extended);
248
249         /* check buffer size */
250
251         if (!suck_check_classbuffer_size(cb, 2))
252                 return false;
253
254         /* get offset delta */
255
256         same_frame_extended->offset_delta = suck_u2(cb);
257
258         return true;
259 }
260
261
262 /* stackmap_get_append_frame ***************************************************
263
264    append_frame {
265        u1 frame_type = APPEND_FRAME;  // 252-254
266            u2 offset_delta;
267            verification_type_info locals[frame_Type - 251];
268    }
269
270 *******************************************************************************/
271
272 static bool stackmap_get_append_frame(classbuffer *cb,
273                                                                           stack_map_frame_t *stack_map_frame)
274 {
275         append_frame_t *append_frame;
276         s4              number_of_locals;
277         s4              i;
278
279         /* for convenience */
280
281         append_frame = &(stack_map_frame->append_frame);
282
283         /* check buffer size */
284
285         if (!suck_check_classbuffer_size(cb, 2))
286                 return false;
287
288         /* get offset delta */
289
290         append_frame->offset_delta = suck_u2(cb);
291
292         /* allocate locals array */
293
294         number_of_locals = append_frame->frame_type - 251;
295
296         append_frame->locals = DMNEW(verification_type_info_t, number_of_locals);
297
298         /* process all locals */
299
300         for (i = 0; i < number_of_locals; i++)
301                 if (!stackmap_get_verification_type_info(cb, &(append_frame->locals[i])))
302                         return false;
303
304         return true;
305 }
306
307
308 /* stackmap_get_full_frame *****************************************************
309
310    full_frame {
311        u1 frame_type = FULL_FRAME;
312            u2 offset_delta;
313            u2 number_of_locals;
314            verification_type_info locals[number_of_locals];
315            u2 number_of_stack_items;
316            verification_type_info stack[number_of_stack_items];
317    }
318
319 *******************************************************************************/
320
321 static bool stackmap_get_full_frame(classbuffer *cb,
322                                                                         stack_map_frame_t *stack_map_frame)
323 {
324         full_frame_t *full_frame;
325         s4 i;
326
327         /* for convenience */
328
329         full_frame = &(stack_map_frame->full_frame);
330
331         /* check buffer size */
332
333         if (!suck_check_classbuffer_size(cb, 2 + 2))
334                 return false;
335
336         /*  get offset delta */
337
338         stack_map_frame->full_frame.offset_delta = suck_u2(cb);
339
340         /* get number of locals */
341
342         full_frame->number_of_locals = suck_u2(cb);
343
344         /* allocate locals array */
345
346         full_frame->locals =
347                 DMNEW(verification_type_info_t, full_frame->number_of_locals);
348
349         /* process all locals */
350
351         for (i = 0; i < full_frame->number_of_locals; i++)
352                 if (!stackmap_get_verification_type_info(cb, &(full_frame->locals[i])))
353                         return false;
354
355         /* get number of stack items */
356
357         if (!suck_check_classbuffer_size(cb, 2))
358                 return false;
359
360         full_frame->number_of_stack_items = suck_u2(cb);
361
362         /* allocate stack array */
363
364         full_frame->stack =
365                 DMNEW(verification_type_info_t, full_frame->number_of_stack_items);
366
367         /* process all stack items */
368
369         for (i = 0; i < full_frame->number_of_stack_items; i++)
370                 if (!stackmap_get_verification_type_info(cb, &(full_frame->stack[i])))
371                         return false;
372
373         return true;
374 }
375
376
377 /* stackmap_load_attribute_stackmaptable ***************************************
378
379    stack_map {
380            u2 attribute_name_index;
381            u4 attribute_length;
382            u2 number_of_entries;
383            stack_map_frame entries[number_of_entries];
384    }
385
386    union stack_map_frame {
387        same_frame;
388            same_locals_1_stack_item_frame;
389            same_locals_1_stack_item_frame_extended;
390            chop_frame;
391            same_frame_extended;
392            append_frame;
393            full_frame;
394    }
395
396    same_frame {
397        u1 frame_type = SAME;  // 0-63
398    }
399
400 *******************************************************************************/
401
402 bool stackmap_load_attribute_stackmaptable(classbuffer *cb, methodinfo *m)
403 {
404         classinfo       *c;
405         stack_map_t     *stack_map;
406         s4               i;
407         u1               frame_type;
408
409         /* get classinfo */
410
411         c = cb->clazz;
412
413         /* allocate stack map structure */
414
415         stack_map = DNEW(stack_map_t);
416
417         STATISTICS(size_stack_map += sizeof(stack_map_t));
418
419         /* check buffer size */
420
421         if (!suck_check_classbuffer_size(cb, 4 + 2))
422                 return false;
423
424         /* attribute_length */
425
426         stack_map->attribute_length = suck_u4(cb);
427
428         if (!suck_check_classbuffer_size(cb, stack_map->attribute_length))
429                 return false;
430
431         /* get number of entries */
432
433         stack_map->number_of_entries = suck_u2(cb);
434
435         /* process all entries */
436
437         stack_map->entries = DMNEW(stack_map_frame_t, stack_map->number_of_entries);
438
439         for (i = 0; i < stack_map->number_of_entries; i++) {
440                 /* get the frame type */
441
442                 frame_type = suck_u1(cb);
443
444                 stack_map->entries[i].frame_type = frame_type;
445
446                 /* process frame */
447
448                 if (frame_type <= FRAME_TYPE_SAME) {
449                         /* same_frame */
450                 }
451                 else if (frame_type <= FRAME_TYPE_SAME_LOCALS_1_STACK_ITEM) {
452                         /* same_locals_1_stack_item_frame */
453
454                         if (!stackmap_get_same_locals_1_stack_item_frame(cb, &(stack_map->entries[i])))
455                                 return false;
456                 }
457                 else if (frame_type <= FRAME_TYPE_RESERVED) {
458                         /* reserved */
459
460                         exceptions_throw_classformaterror(c, "reserved frame type");
461                         return false;
462                 }
463                 else if (frame_type == FRAME_TYPE_SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
464                         /* same_locals_1_stack_item_frame_extended */
465
466                         if (!stackmap_get_same_locals_1_stack_item_frame_extended(cb, &(stack_map->entries[i])))
467                                 return false;
468                 }
469                 else if (frame_type <= FRAME_TYPE_CHOP) {
470                         /* chop_frame */
471
472                         if (!stackmap_get_chop_frame(cb, &(stack_map->entries[i])))
473                                 return false;
474                 }
475                 else if (frame_type == FRAME_TYPE_SAME_FRAME_EXTENDED) {
476                         /* same_frame_extended */
477
478                         if (!stackmap_get_same_frame_extended(cb, &(stack_map->entries[i])))
479                                 return false;
480                 }
481                 else if (frame_type <= FRAME_TYPE_APPEND) {
482                         /* append_frame */
483
484                         if (!stackmap_get_append_frame(cb, &(stack_map->entries[i])))
485                                 return false;
486                 }
487                 else if (frame_type == FRAME_TYPE_FULL_FRAME) {
488                         /* full_frame */
489
490                         if (!stackmap_get_full_frame(cb, &(stack_map->entries[i])))
491                                 return false;
492                 }
493         }
494
495         /* store stack map in method structure */
496
497 #if 0
498         /* currently not used */
499
500         m->stack_map = stack_map;
501 #endif
502
503         return true;
504 }
505
506
507 /*
508  * These are local overrides for various environment variables in Emacs.
509  * Please do not remove this and leave it at the end of the file, where
510  * Emacs will automagically detect them.
511  * ---------------------------------------------------------------------
512  * Local variables:
513  * mode: c
514  * indent-tabs-mode: t
515  * c-basic-offset: 4
516  * tab-width: 4
517  * End:
518  * vim:noexpandtab:sw=4:ts=4:
519  */