| OLD | NEW |
| (Empty) |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import module as mojom | |
| 6 | |
| 7 # This module provides a mechanism for determining the packed order and offsets | |
| 8 # of a mojom.Struct. | |
| 9 # | |
| 10 # ps = pack.PackedStruct(struct) | |
| 11 # ps.packed_fields will access a list of PackedField objects, each of which | |
| 12 # will have an offset, a size and a bit (for mojom.BOOLs). | |
| 13 | |
| 14 # Size of struct header in bytes: num_bytes [4B] + version [4B]. | |
| 15 HEADER_SIZE = 8 | |
| 16 | |
| 17 class PackedField(object): | |
| 18 kind_to_size = { | |
| 19 mojom.BOOL: 1, | |
| 20 mojom.INT8: 1, | |
| 21 mojom.UINT8: 1, | |
| 22 mojom.INT16: 2, | |
| 23 mojom.UINT16: 2, | |
| 24 mojom.INT32: 4, | |
| 25 mojom.UINT32: 4, | |
| 26 mojom.FLOAT: 4, | |
| 27 mojom.HANDLE: 4, | |
| 28 mojom.MSGPIPE: 4, | |
| 29 mojom.SHAREDBUFFER: 4, | |
| 30 mojom.DCPIPE: 4, | |
| 31 mojom.DPPIPE: 4, | |
| 32 mojom.NULLABLE_HANDLE: 4, | |
| 33 mojom.NULLABLE_MSGPIPE: 4, | |
| 34 mojom.NULLABLE_SHAREDBUFFER: 4, | |
| 35 mojom.NULLABLE_DCPIPE: 4, | |
| 36 mojom.NULLABLE_DPPIPE: 4, | |
| 37 mojom.INT64: 8, | |
| 38 mojom.UINT64: 8, | |
| 39 mojom.DOUBLE: 8, | |
| 40 mojom.STRING: 8, | |
| 41 mojom.NULLABLE_STRING: 8 | |
| 42 } | |
| 43 | |
| 44 @classmethod | |
| 45 def GetSizeForKind(cls, kind): | |
| 46 if isinstance(kind, (mojom.Array, mojom.Map, mojom.Struct, | |
| 47 mojom.Interface)): | |
| 48 return 8 | |
| 49 if isinstance(kind, mojom.Union): | |
| 50 return 16 | |
| 51 if isinstance(kind, mojom.InterfaceRequest): | |
| 52 kind = mojom.MSGPIPE | |
| 53 if isinstance(kind, mojom.Enum): | |
| 54 # TODO(mpcomplete): what about big enums? | |
| 55 return cls.kind_to_size[mojom.INT32] | |
| 56 if not kind in cls.kind_to_size: | |
| 57 raise Exception("Invalid kind: %s" % kind.spec) | |
| 58 return cls.kind_to_size[kind] | |
| 59 | |
| 60 def __init__(self, field): | |
| 61 """ | |
| 62 Args: | |
| 63 field: the original field. | |
| 64 """ | |
| 65 self.field = field | |
| 66 self.index = field.declaration_order | |
| 67 self.ordinal = field.computed_ordinal | |
| 68 self.size = self.GetSizeForKind(field.kind) | |
| 69 self.offset = field.computed_offset | |
| 70 self.bit = field.computed_bit | |
| 71 self.min_version = field.computed_min_version | |
| 72 | |
| 73 | |
| 74 def GetPad(offset, alignment): | |
| 75 """Returns the pad necessary to reserve space so that |offset + pad| equals to | |
| 76 some multiple of |alignment|.""" | |
| 77 return (alignment - (offset % alignment)) % alignment | |
| 78 | |
| 79 | |
| 80 class PackedStruct(object): | |
| 81 def __init__(self, struct): | |
| 82 self.struct = struct | |
| 83 | |
| 84 # |packed_fields_in_ordinal_order| contains all the fields, | |
| 85 # in ordinal order. | |
| 86 self.packed_fields_in_ordinal_order = [PackedField(field) | |
| 87 for field in struct.fields_in_ordinal_order] | |
| 88 | |
| 89 # |packed_fields| refers to the same fields as | |
| 90 # |packed_fields_in_ordinal_order|, but in increasing offset order. | |
| 91 self.packed_fields = [field for field in | |
| 92 self.packed_fields_in_ordinal_order] | |
| 93 self.packed_fields.sort(key=lambda f: (f.offset, f.bit)) | |
| 94 | |
| 95 class ByteInfo(object): | |
| 96 def __init__(self): | |
| 97 self.is_padding = False | |
| 98 self.packed_fields = [] | |
| 99 | |
| 100 | |
| 101 def GetByteLayout(packed_struct): | |
| 102 total_payload_size = packed_struct.struct.versions[-1].num_bytes - HEADER_SIZE | |
| 103 bytes = [ByteInfo() for i in xrange(total_payload_size)] | |
| 104 | |
| 105 limit_of_previous_field = 0 | |
| 106 for packed_field in packed_struct.packed_fields: | |
| 107 for i in xrange(limit_of_previous_field, packed_field.offset): | |
| 108 bytes[i].is_padding = True | |
| 109 bytes[packed_field.offset].packed_fields.append(packed_field) | |
| 110 limit_of_previous_field = packed_field.offset + packed_field.size | |
| 111 | |
| 112 for i in xrange(limit_of_previous_field, len(bytes)): | |
| 113 bytes[i].is_padding = True | |
| 114 | |
| 115 for byte in bytes: | |
| 116 # A given byte cannot both be padding and have a fields packed into it. | |
| 117 assert not (byte.is_padding and byte.packed_fields) | |
| 118 | |
| 119 return bytes | |
| 120 | |
| 121 | |
| 122 class VersionInfo(object): | |
| 123 def __init__(self, version, num_fields, num_bytes): | |
| 124 self.version = version | |
| 125 self.num_fields = num_fields | |
| 126 self.num_bytes = num_bytes | |
| 127 | |
| OLD | NEW |