/* src/vm/stackmap.c - class attribute StackMapTable Copyright (C) 2006, 2007, 2008 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include "vm/types.h" #include "mm/memory.hpp" #include "vm/class.hpp" #include "vm/exceptions.hpp" #include "vm/method.hpp" #include "vm/options.h" #include "vm/stackmap.h" #include "vm/statistics.h" #include "vm/suck.hpp" /* stackmap_get_verification_type_info ***************************************** union verification_type_info { Top_variable_info; Integer_variable_info; Float_variable_info; Long_variable_info; Double_variable_info; Null_variable_info; UninitializedThis_variable_info; Object_variable_info; Uninitialized_variable_info; } Top_variable_info { u1 tag = ITEM_Top; // 0 } Integer_variable_info { u1 tag = ITEM_Integer; // 1 } Float_variable_info { u1 tag = ITEM_Float; // 2 } Long_variable_info { u1 tag = ITEM_Long; // 4 } Double_variable_info { u1 tag = ITEM_Double; // 3 } Null_variable_info { u1 tag = ITEM_Null; // 5 } UninitializedThis_variable_info { u1 tag = ITEM_UninitializedThis; // 6 } Object_variable_info { u1 tag = ITEM_Object; // 7 u2 cpool_index; } Uninitialized_variable_info { u1 tag = ITEM_Uninitialized; // 8 u2 offset; } *******************************************************************************/ static bool stackmap_get_verification_type_info(classbuffer *cb, verification_type_info_t *verification_type_info) { /* get verification type */ if (!suck_check_classbuffer_size(cb, 1)) return false; verification_type_info->tag = suck_u1(cb); /* process the tag */ switch (verification_type_info->tag) { case ITEM_Top: case ITEM_Integer: case ITEM_Float: case ITEM_Long: case ITEM_Double: case ITEM_Null: case ITEM_UninitializedThis: break; case ITEM_Object: /* get constant pool index */ if (!suck_check_classbuffer_size(cb, 2)) return false; verification_type_info->Object_variable_info.cpool_index = suck_u2(cb); break; case ITEM_Uninitialized: /* get offset */ if (!suck_check_classbuffer_size(cb, 2)) return false; verification_type_info->Uninitialized_variable_info.offset = suck_u2(cb); break; } return true; } /* stackmap_get_same_locals_1_stack_item_frame ********************************* same_locals_1_stack_item_frame { u1 frame_type = SAME_LOCALS_1_STACK_ITEM; // 64-127 verification_type_info stack[1]; } *******************************************************************************/ static bool stackmap_get_same_locals_1_stack_item_frame(classbuffer *cb, stack_map_frame_t *stack_map_frame) { same_locals_1_stack_item_frame_t *same_locals_1_stack_item_frame; /* for convenience */ same_locals_1_stack_item_frame = &(stack_map_frame->same_locals_1_stack_item_frame); if (!stackmap_get_verification_type_info(cb, &(same_locals_1_stack_item_frame->stack[0]))) return false; return true; } /* stackmap_get_same_locals_1_stack_item_frame_extended ************************ same_locals_1_stack_item_frame_extended { u1 frame_type = SAME_LOCALS_1_STACK_ITEM_EXTENDED; // 247 u2 offset_delta; verification_type_info stack[1]; } *******************************************************************************/ static bool stackmap_get_same_locals_1_stack_item_frame_extended(classbuffer *cb, stack_map_frame_t *stack_map_frame) { same_locals_1_stack_item_frame_extended_t *same_locals_1_stack_item_frame_extended; /* for convenience */ same_locals_1_stack_item_frame_extended = &(stack_map_frame->same_locals_1_stack_item_frame_extended); /* check buffer size */ if (!suck_check_classbuffer_size(cb, 2)) return false; /* get offset delta */ same_locals_1_stack_item_frame_extended->offset_delta = suck_u2(cb); /* process stack */ if (!stackmap_get_verification_type_info(cb, &(same_locals_1_stack_item_frame_extended->stack[0]))) return false; return true; } /* stackmap_get_chop_frame ***************************************************** chop_frame { u1 frame_type = CHOP_FRAME; // 248-250 u2 offset_delta; } *******************************************************************************/ static bool stackmap_get_chop_frame(classbuffer *cb, stack_map_frame_t *stack_map_frame) { chop_frame_t *chop_frame; /* for convenience */ chop_frame = &(stack_map_frame->chop_frame); /* check buffer size */ if (!suck_check_classbuffer_size(cb, 2)) return false; /* get offset delta */ chop_frame->offset_delta = suck_u2(cb); return true; } /* stackmap_get_same_frame_extended ******************************************** same_frame_extended { u1 frame_type = SAME_FRAME_EXTENDED; // 251 u2 offset_delta; } *******************************************************************************/ static bool stackmap_get_same_frame_extended(classbuffer *cb, stack_map_frame_t *stack_map_frame) { same_frame_extended_t *same_frame_extended; /* for convenience */ same_frame_extended = &(stack_map_frame->same_frame_extended); /* check buffer size */ if (!suck_check_classbuffer_size(cb, 2)) return false; /* get offset delta */ same_frame_extended->offset_delta = suck_u2(cb); return true; } /* stackmap_get_append_frame *************************************************** append_frame { u1 frame_type = APPEND_FRAME; // 252-254 u2 offset_delta; verification_type_info locals[frame_Type - 251]; } *******************************************************************************/ static bool stackmap_get_append_frame(classbuffer *cb, stack_map_frame_t *stack_map_frame) { append_frame_t *append_frame; s4 number_of_locals; s4 i; /* for convenience */ append_frame = &(stack_map_frame->append_frame); /* check buffer size */ if (!suck_check_classbuffer_size(cb, 2)) return false; /* get offset delta */ append_frame->offset_delta = suck_u2(cb); /* allocate locals array */ number_of_locals = append_frame->frame_type - 251; append_frame->locals = DMNEW(verification_type_info_t, number_of_locals); /* process all locals */ for (i = 0; i < number_of_locals; i++) if (!stackmap_get_verification_type_info(cb, &(append_frame->locals[i]))) return false; return true; } /* stackmap_get_full_frame ***************************************************** full_frame { u1 frame_type = FULL_FRAME; u2 offset_delta; u2 number_of_locals; verification_type_info locals[number_of_locals]; u2 number_of_stack_items; verification_type_info stack[number_of_stack_items]; } *******************************************************************************/ static bool stackmap_get_full_frame(classbuffer *cb, stack_map_frame_t *stack_map_frame) { full_frame_t *full_frame; s4 i; /* for convenience */ full_frame = &(stack_map_frame->full_frame); /* check buffer size */ if (!suck_check_classbuffer_size(cb, 2 + 2)) return false; /* get offset delta */ stack_map_frame->full_frame.offset_delta = suck_u2(cb); /* get number of locals */ full_frame->number_of_locals = suck_u2(cb); /* allocate locals array */ full_frame->locals = DMNEW(verification_type_info_t, full_frame->number_of_locals); /* process all locals */ for (i = 0; i < full_frame->number_of_locals; i++) if (!stackmap_get_verification_type_info(cb, &(full_frame->locals[i]))) return false; /* get number of stack items */ if (!suck_check_classbuffer_size(cb, 2)) return false; full_frame->number_of_stack_items = suck_u2(cb); /* allocate stack array */ full_frame->stack = DMNEW(verification_type_info_t, full_frame->number_of_stack_items); /* process all stack items */ for (i = 0; i < full_frame->number_of_stack_items; i++) if (!stackmap_get_verification_type_info(cb, &(full_frame->stack[i]))) return false; return true; } /* stackmap_load_attribute_stackmaptable *************************************** stack_map { u2 attribute_name_index; u4 attribute_length; u2 number_of_entries; stack_map_frame entries[number_of_entries]; } union stack_map_frame { same_frame; same_locals_1_stack_item_frame; same_locals_1_stack_item_frame_extended; chop_frame; same_frame_extended; append_frame; full_frame; } same_frame { u1 frame_type = SAME; // 0-63 } *******************************************************************************/ bool stackmap_load_attribute_stackmaptable(classbuffer *cb, methodinfo *m) { classinfo *c; stack_map_t *stack_map; s4 i; u1 frame_type; /* get classinfo */ c = cb->clazz; /* allocate stack map structure */ stack_map = DNEW(stack_map_t); STATISTICS(size_stack_map += sizeof(stack_map_t)); /* check buffer size */ if (!suck_check_classbuffer_size(cb, 4 + 2)) return false; /* attribute_length */ stack_map->attribute_length = suck_u4(cb); if (!suck_check_classbuffer_size(cb, stack_map->attribute_length)) return false; /* get number of entries */ stack_map->number_of_entries = suck_u2(cb); /* process all entries */ stack_map->entries = DMNEW(stack_map_frame_t, stack_map->number_of_entries); for (i = 0; i < stack_map->number_of_entries; i++) { /* get the frame type */ frame_type = suck_u1(cb); stack_map->entries[i].frame_type = frame_type; /* process frame */ if (frame_type <= FRAME_TYPE_SAME) { /* same_frame */ } else if (frame_type <= FRAME_TYPE_SAME_LOCALS_1_STACK_ITEM) { /* same_locals_1_stack_item_frame */ if (!stackmap_get_same_locals_1_stack_item_frame(cb, &(stack_map->entries[i]))) return false; } else if (frame_type <= FRAME_TYPE_RESERVED) { /* reserved */ exceptions_throw_classformaterror(c, "reserved frame type"); return false; } else if (frame_type == FRAME_TYPE_SAME_LOCALS_1_STACK_ITEM_EXTENDED) { /* same_locals_1_stack_item_frame_extended */ if (!stackmap_get_same_locals_1_stack_item_frame_extended(cb, &(stack_map->entries[i]))) return false; } else if (frame_type <= FRAME_TYPE_CHOP) { /* chop_frame */ if (!stackmap_get_chop_frame(cb, &(stack_map->entries[i]))) return false; } else if (frame_type == FRAME_TYPE_SAME_FRAME_EXTENDED) { /* same_frame_extended */ if (!stackmap_get_same_frame_extended(cb, &(stack_map->entries[i]))) return false; } else if (frame_type <= FRAME_TYPE_APPEND) { /* append_frame */ if (!stackmap_get_append_frame(cb, &(stack_map->entries[i]))) return false; } else if (frame_type == FRAME_TYPE_FULL_FRAME) { /* full_frame */ if (!stackmap_get_full_frame(cb, &(stack_map->entries[i]))) return false; } } /* store stack map in method structure */ #if 0 /* currently not used */ m->stack_map = stack_map; #endif return true; } /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where * Emacs will automagically detect them. * --------------------------------------------------------------------- * Local variables: * mode: c * indent-tabs-mode: t * c-basic-offset: 4 * tab-width: 4 * End: * vim:noexpandtab:sw=4:ts=4: */