Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(347)

Side by Side Diff: mojo/public/tools/bindings/pylib/mojom/generate/pack.py

Issue 1824263002: Mojom backend: Stop re-computing version info and field packing data. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2013 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import module as mojom 5 import module as mojom
6 6
7 # This module provides a mechanism for determining the packed order and offsets 7 # This module provides a mechanism for determining the packed order and offsets
8 # of a mojom.Struct. 8 # of a mojom.Struct.
9 # 9 #
10 # ps = pack.PackedStruct(struct) 10 # ps = pack.PackedStruct(struct)
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 return 16 50 return 16
51 if isinstance(kind, mojom.InterfaceRequest): 51 if isinstance(kind, mojom.InterfaceRequest):
52 kind = mojom.MSGPIPE 52 kind = mojom.MSGPIPE
53 if isinstance(kind, mojom.Enum): 53 if isinstance(kind, mojom.Enum):
54 # TODO(mpcomplete): what about big enums? 54 # TODO(mpcomplete): what about big enums?
55 return cls.kind_to_size[mojom.INT32] 55 return cls.kind_to_size[mojom.INT32]
56 if not kind in cls.kind_to_size: 56 if not kind in cls.kind_to_size:
57 raise Exception("Invalid kind: %s" % kind.spec) 57 raise Exception("Invalid kind: %s" % kind.spec)
58 return cls.kind_to_size[kind] 58 return cls.kind_to_size[kind]
59 59
60 @classmethod 60 def __init__(self, field):
61 def GetAlignmentForKind(cls, kind):
62 if isinstance(kind, mojom.Interface):
63 return 4
64 if isinstance(kind, mojom.Union):
65 return 8
66 return cls.GetSizeForKind(kind)
67
68 def __init__(self, field, index, ordinal):
69 """ 61 """
70 Args: 62 Args:
71 field: the original field. 63 field: the original field.
72 index: the position of the original field in the struct.
73 ordinal: the ordinal of the field for serialization.
74 """ 64 """
75 self.field = field 65 self.field = field
76 self.index = index 66 self.index = field.declaration_order
77 self.ordinal = ordinal 67 self.ordinal = field.computed_ordinal
78 self.size = self.GetSizeForKind(field.kind) 68 self.size = self.GetSizeForKind(field.kind)
79 self.alignment = self.GetAlignmentForKind(field.kind) 69 self.offset = field.computed_offset
80 self.offset = None 70 self.bit = field.computed_bit
81 self.bit = None 71 self.min_version = field.computed_min_version
82 self.min_version = None
83 72
84 73
85 def GetPad(offset, alignment): 74 def GetPad(offset, alignment):
86 """Returns the pad necessary to reserve space so that |offset + pad| equals to 75 """Returns the pad necessary to reserve space so that |offset + pad| equals to
87 some multiple of |alignment|.""" 76 some multiple of |alignment|."""
88 return (alignment - (offset % alignment)) % alignment 77 return (alignment - (offset % alignment)) % alignment
89 78
90 79
91 def GetFieldOffset(field, last_field):
92 """Returns a 2-tuple of the field offset and bit (for BOOLs)."""
93 if (field.field.kind == mojom.BOOL and
94 last_field.field.kind == mojom.BOOL and
95 last_field.bit < 7):
96 return (last_field.offset, last_field.bit + 1)
97
98 offset = last_field.offset + last_field.size
99 pad = GetPad(offset, field.alignment)
100 return (offset + pad, 0)
101
102
103 def GetPayloadSizeUpToField(field):
104 """Returns the payload size (not including struct header) if |field| is the
105 last field.
106 """
107 if not field:
108 return 0
109 offset = field.offset + field.size
110 pad = GetPad(offset, 8)
111 return offset + pad
112
113
114 class PackedStruct(object): 80 class PackedStruct(object):
115 def __init__(self, struct): 81 def __init__(self, struct):
116 self.struct = struct 82 self.struct = struct
117 # |packed_fields| contains all the fields, in increasing offset order.
118 self.packed_fields = []
119 # |packed_fields_in_ordinal_order| refers to the same fields as
120 # |packed_fields|, but in ordinal order.
121 self.packed_fields_in_ordinal_order = []
122 83
123 # No fields. 84 # |packed_fields_in_ordinal_order| contains all the fields,
124 if (len(struct.fields) == 0): 85 # in ordinal order.
125 return 86 self.packed_fields_in_ordinal_order = [PackedField(field)
87 for field in struct.fields_in_ordinal_order]
126 88
127 # Start by sorting by ordinal. 89 # |packed_fields| refers to the same fields as
128 src_fields = self.packed_fields_in_ordinal_order 90 # |packed_fields_in_ordinal_order|, but in increasing offset order.
129 ordinal = 0 91 self.packed_fields = [field for field in
130 for index, field in enumerate(struct.fields): 92 self.packed_fields_in_ordinal_order]
131 if field.ordinal is not None: 93 self.packed_fields.sort(key=lambda f: (f.offset, f.bit))
132 ordinal = field.ordinal
133 src_fields.append(PackedField(field, index, ordinal))
134 ordinal += 1
135 src_fields.sort(key=lambda field: field.ordinal)
136
137 # Set |min_version| for each field.
138 next_min_version = 0
139 for packed_field in src_fields:
140 if packed_field.field.min_version is None:
141 assert next_min_version == 0
142 else:
143 assert packed_field.field.min_version >= next_min_version
144 next_min_version = packed_field.field.min_version
145 packed_field.min_version = next_min_version
146
147 if (packed_field.min_version != 0 and
148 mojom.IsReferenceKind(packed_field.field.kind) and
149 not packed_field.field.kind.is_nullable):
150 raise Exception("Non-nullable fields are only allowed in version 0 of "
151 "a struct. %s.%s is defined with [MinVersion=%d]."
152 % (self.struct.name, packed_field.field.name,
153 packed_field.min_version))
154
155 src_field = src_fields[0]
156 src_field.offset = 0
157 src_field.bit = 0
158 dst_fields = self.packed_fields
159 dst_fields.append(src_field)
160
161 # Then find first slot that each field will fit.
162 for src_field in src_fields[1:]:
163 last_field = dst_fields[0]
164 for i in xrange(1, len(dst_fields)):
165 next_field = dst_fields[i]
166 offset, bit = GetFieldOffset(src_field, last_field)
167 if offset + src_field.size <= next_field.offset:
168 # Found hole.
169 src_field.offset = offset
170 src_field.bit = bit
171 dst_fields.insert(i, src_field)
172 break
173 last_field = next_field
174 if src_field.offset is None:
175 # Add to end
176 src_field.offset, src_field.bit = GetFieldOffset(src_field, last_field)
177 dst_fields.append(src_field)
178
179 94
180 class ByteInfo(object): 95 class ByteInfo(object):
181 def __init__(self): 96 def __init__(self):
182 self.is_padding = False 97 self.is_padding = False
183 self.packed_fields = [] 98 self.packed_fields = []
184 99
185 100
186 def GetByteLayout(packed_struct): 101 def GetByteLayout(packed_struct):
187 total_payload_size = GetPayloadSizeUpToField( 102 total_payload_size = packed_struct.struct.versions[-1].num_bytes - HEADER_SIZE
188 packed_struct.packed_fields[-1] if packed_struct.packed_fields else None)
189 bytes = [ByteInfo() for i in xrange(total_payload_size)] 103 bytes = [ByteInfo() for i in xrange(total_payload_size)]
190 104
191 limit_of_previous_field = 0 105 limit_of_previous_field = 0
192 for packed_field in packed_struct.packed_fields: 106 for packed_field in packed_struct.packed_fields:
193 for i in xrange(limit_of_previous_field, packed_field.offset): 107 for i in xrange(limit_of_previous_field, packed_field.offset):
194 bytes[i].is_padding = True 108 bytes[i].is_padding = True
195 bytes[packed_field.offset].packed_fields.append(packed_field) 109 bytes[packed_field.offset].packed_fields.append(packed_field)
196 limit_of_previous_field = packed_field.offset + packed_field.size 110 limit_of_previous_field = packed_field.offset + packed_field.size
197 111
198 for i in xrange(limit_of_previous_field, len(bytes)): 112 for i in xrange(limit_of_previous_field, len(bytes)):
199 bytes[i].is_padding = True 113 bytes[i].is_padding = True
200 114
201 for byte in bytes: 115 for byte in bytes:
202 # A given byte cannot both be padding and have a fields packed into it. 116 # A given byte cannot both be padding and have a fields packed into it.
203 assert not (byte.is_padding and byte.packed_fields) 117 assert not (byte.is_padding and byte.packed_fields)
204 118
205 return bytes 119 return bytes
206 120
207 121
208 class VersionInfo(object): 122 class VersionInfo(object):
209 def __init__(self, version, num_fields, num_bytes): 123 def __init__(self, version, num_fields, num_bytes):
210 self.version = version 124 self.version = version
211 self.num_fields = num_fields 125 self.num_fields = num_fields
212 self.num_bytes = num_bytes 126 self.num_bytes = num_bytes
213 127
214
215 def GetVersionInfo(packed_struct):
216 """Get version information for a struct.
217
218 Args:
219 packed_struct: A PackedStruct instance.
220
221 Returns:
222 A non-empty list of VersionInfo instances, sorted by version in increasing
223 order.
224 Note: The version numbers may not be consecutive.
225 """
226 versions = []
227 last_version = 0
228 last_num_fields = 0
229 last_payload_size = 0
230
231 for packed_field in packed_struct.packed_fields_in_ordinal_order:
232 if packed_field.min_version != last_version:
233 versions.append(
234 VersionInfo(last_version, last_num_fields,
235 last_payload_size + HEADER_SIZE))
236 last_version = packed_field.min_version
237
238 last_num_fields += 1
239 # The fields are iterated in ordinal order here. However, the size of a
240 # version is determined by the last field of that version in pack order,
241 # instead of ordinal order. Therefore, we need to calculate the max value.
242 last_payload_size = max(GetPayloadSizeUpToField(packed_field),
243 last_payload_size)
244
245 assert len(versions) == 0 or last_num_fields != versions[-1].num_fields
246 versions.append(VersionInfo(last_version, last_num_fields,
247 last_payload_size + HEADER_SIZE))
248 return versions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698