1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved. 21e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 31e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# found in the LICENSE file. 41e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport module as mojom 61e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 70529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch# This module provides a mechanism for determining the packed order and offsets 81e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# of a mojom.Struct. 91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# 100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch# ps = pack.PackedStruct(struct) 111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# ps.packed_fields will access a list of PackedField objects, each of which 121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# will have an offset, a size and a bit (for mojom.BOOLs). 131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)class PackedField(object): 151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) kind_to_size = { 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.BOOL: 1, 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.INT8: 1, 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.UINT8: 1, 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.INT16: 2, 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.UINT16: 2, 215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.INT32: 4, 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.UINT32: 4, 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.FLOAT: 4, 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.HANDLE: 4, 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.MSGPIPE: 4, 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.SHAREDBUFFER: 4, 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.DCPIPE: 4, 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.DPPIPE: 4, 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.NULLABLE_HANDLE: 4, 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.NULLABLE_MSGPIPE: 4, 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.NULLABLE_SHAREDBUFFER: 4, 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.NULLABLE_DCPIPE: 4, 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.NULLABLE_DPPIPE: 4, 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.INT64: 8, 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.UINT64: 8, 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.DOUBLE: 8, 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.STRING: 8, 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mojom.NULLABLE_STRING: 8 391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) @classmethod 421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) def GetSizeForKind(cls, kind): 43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if isinstance(kind, (mojom.Array, mojom.Struct, mojom.FixedArray)): 441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return 8 45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if isinstance(kind, mojom.Interface) or \ 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) isinstance(kind, mojom.InterfaceRequest): 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kind = mojom.MSGPIPE 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if isinstance(kind, mojom.Enum): 49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) # TODO(mpcomplete): what about big enums? 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return cls.kind_to_size[mojom.INT32] 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if not kind in cls.kind_to_size: 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) raise Exception("Invalid kind: %s" % kind.spec) 531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return cls.kind_to_size[kind] 541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) def __init__(self, field, ordinal): 561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self.field = field 571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self.ordinal = ordinal 581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self.size = self.GetSizeForKind(field.kind) 591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self.offset = None 601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self.bit = None 611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# Returns the pad necessary to reserve space for alignment of |size|. 641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def GetPad(offset, size): 651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return (size - (offset % size)) % size 661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# Returns a 2-tuple of the field offset and bit (for BOOLs) 691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)def GetFieldOffset(field, last_field): 701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if field.field.kind == mojom.BOOL and \ 711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) last_field.field.kind == mojom.BOOL and \ 721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) last_field.bit < 7: 731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return (last_field.offset, last_field.bit + 1) 741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) offset = last_field.offset + last_field.size 761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) pad = GetPad(offset, field.size) 771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return (offset + pad, 0) 781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)class PackedStruct(object): 811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) def __init__(self, struct): 821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self.struct = struct 831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) self.packed_fields = [] 841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) # No fields. 861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (len(struct.fields) == 0): 871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return 881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) # Start by sorting by ordinal. 901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) src_fields = [] 915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ordinal = 0 921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for field in struct.fields: 931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if field.ordinal is not None: 941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ordinal = field.ordinal 951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) src_fields.append(PackedField(field, ordinal)) 961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ordinal += 1 971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) src_fields.sort(key=lambda field: field.ordinal) 981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) src_field = src_fields[0] 1001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) src_field.offset = 0 1011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) src_field.bit = 0 1021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) # dst_fields will contain each of the fields, in increasing offset order. 1031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) dst_fields = self.packed_fields 1041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) dst_fields.append(src_field) 1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) # Then find first slot that each field will fit. 1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for src_field in src_fields[1:]: 1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) last_field = dst_fields[0] 1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for i in xrange(1, len(dst_fields)): 1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) next_field = dst_fields[i] 1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) offset, bit = GetFieldOffset(src_field, last_field) 1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if offset + src_field.size <= next_field.offset: 1131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) # Found hole. 1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) src_field.offset = offset 1151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) src_field.bit = bit 1161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) dst_fields.insert(i, src_field) 1171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) break 1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) last_field = next_field 1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if src_field.offset is None: 1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) # Add to end 1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) src_field.offset, src_field.bit = GetFieldOffset(src_field, last_field) 1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) dst_fields.append(src_field) 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def GetTotalSize(self): 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if not self.packed_fields: 1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return 0 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) last_field = self.packed_fields[-1] 128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) offset = last_field.offset + last_field.size 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) pad = GetPad(offset, 8) 1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return offset + pad 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class ByteInfo(object): 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def __init__(self): 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.is_padding = False 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.packed_fields = [] 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)def GetByteLayout(packed_struct): 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bytes = [ByteInfo() for i in xrange(packed_struct.GetTotalSize())] 141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) limit_of_previous_field = 0 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for packed_field in packed_struct.packed_fields: 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for i in xrange(limit_of_previous_field, packed_field.offset): 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bytes[i].is_padding = True 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bytes[packed_field.offset].packed_fields.append(packed_field) 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) limit_of_previous_field = packed_field.offset + packed_field.size 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for i in xrange(limit_of_previous_field, len(bytes)): 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bytes[i].is_padding = True 151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for byte in bytes: 153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) # A given byte cannot both be padding and have a fields packed into it. 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) assert not (byte.is_padding and byte.packed_fields) 155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return bytes 157