Source code for jawa.attributes.stack_map_table

from itertools import repeat

from jawa.attribute import Attribute
from jawa.util.verifier import VerificationTypes

# These types are followed by an additional u2.
TYPES_WITH_EXTRA = (
    VerificationTypes.ITEM_Object,
    VerificationTypes.ITEM_Uninitialized
)


[docs]class StackMapFrame(object): __slots__ = ( 'frame_type', 'frame_offset', 'frame_locals', 'frame_stack' ) def __init__(self, frame_type): self.frame_type = frame_type self.frame_offset = 0 self.frame_locals = [] self.frame_stack = [] def __repr__(self): return ( u'<StackMapFrame(type={s.frame_type!r},' u'offset={s.frame_offset!r},' u'locals={s.frame_locals!r},' u'stack={s.frame_stack!r})>' ).format(s=self)
[docs]class StackMapTableAttribute(Attribute): """ .. note:: Consider this experimental. This is an unnecessary 'feature' added in Java6 that even the official JDK has multiple bugs with. Proper generation of a StackMapTableAttribute requires a complete class hierarchy among other things. """ ADDED_IN = '6.0.0' MINIMUM_CLASS_VERSION = (50, 0) def __init__(self, table, name_index=None): super(StackMapTableAttribute, self).__init__( table, name_index or table.cf.constants.create_utf8( 'StackMapTable' ).index ) self.frames = []
[docs] def unpack(self, info): # Described in "4.7.4. The StackMapTable Attribute" length = info.u2() # Start with a null-state FULL_FRAME. previous_frame = StackMapFrame(255) for i in range(length): frame_type = info.u1() frame = StackMapFrame(frame_type) if frame_type < 64: # 0 to 63 are SAME_FRAME if i == 0: frame.frame_offset = frame_type else: frame.frame_offset = previous_frame.frame_offset + \ frame_type + 1 frame.frame_locals = previous_frame.frame_locals self.frames.append(frame) previous_frame = frame continue elif frame_type < 128: # 64 to 127 are SAME_LOCALS_1_STACK_ITEM if i == 0: frame.frame_offset = frame_type - 64 else: frame.frame_offset = previous_frame.frame_offset + \ frame_type - 63 frame.frame_locals = previous_frame.frame_locals frame.frame_stack = list( self._unpack_verification_type_info(info, 1) ) self.frames.append(frame) previous_frame = frame continue elif frame_type < 247: # Reserved types, we may be trying to parse a ClassFile that's # newer than we can handle. raise NotImplementedError() # All other types have an additional offset frame_offset = info.u2() if frame_type == 247: # SAME_LOCALS_1_STACK_ITEM_EXTENDED if i == 0: frame.frame_offset = frame_offset else: frame.frame_offset = previous_frame.frame_offset + \ frame_offset + 1 frame.frame_locals = previous_frame.frame_locals frame.frame_stack = list( self._unpack_verification_type_info( info, 1 ) ) elif frame_type < 251: # CHOP if i == 0: frame.frame_offset = frame_offset else: frame.frame_offset = previous_frame.frame_offset + \ frame_offset + 1 frame.frame_locals = previous_frame.frame_locals[ 0:251 - frame_type ] elif frame_type == 251: # SAME_FRAME_EXTENDED if i == 0: frame.frame_offset = frame_offset else: frame.frame_offset = previous_frame.frame_offset + \ frame_offset + 1 frame.frame_locals = previous_frame.frame_locals elif frame_type < 255: # APPEND if i == 0: frame.frame_offset = frame_offset else: frame.frame_offset = previous_frame.frame_offset + \ frame_offset + 1 frame.frame_locals = previous_frame.frame_locals + list( self._unpack_verification_type_info( info, frame_type - 251 ) ) elif frame_type == 255: # FULL_FRAME if i == 0: frame.frame_offset = frame_offset else: frame.frame_offset = previous_frame.frame_offset + \ frame_offset + 1 frame.frame_locals = list(self._unpack_verification_type_info( info, info.u2() )) frame.frame_stack = list(self._unpack_verification_type_info( info, info.u2() )) self.frames.append(frame) previous_frame = frame
@staticmethod def _unpack_verification_type_info(info, count): # Unpacks the verification_type_info structure, used for both locals # and the stack. for _ in repeat(None, count): tag = info.u1() if tag in TYPES_WITH_EXTRA: yield (tag, info.u2()) else: yield (tag,)
[docs] def pack(self): raise NotImplementedError()