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

Side by Side Diff: pkg/analyzer/lib/src/summary/flat_buffers.dart

Issue 1568943003: Share VTable(s) in FlatBuffers. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer.src.summary.flat_buffers; 5 library analyzer.src.summary.flat_buffers;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 import 'dart:convert'; 8 import 'dart:convert';
9 import 'dart:typed_data'; 9 import 'dart:typed_data';
10 10
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 } 58 }
59 } 59 }
60 } 60 }
61 61
62 /** 62 /**
63 * Class that helps building flat buffers. 63 * Class that helps building flat buffers.
64 */ 64 */
65 class Builder { 65 class Builder {
66 final int initialSize; 66 final int initialSize;
67 67
68 /**
69 * The list of existing VTable(s).
70 */
71 final List<_VTable> _vTables = <_VTable>[];
72
68 ByteData _buf; 73 ByteData _buf;
69 74
70 /** 75 /**
71 * The maximum alignment that has been seen so far. If [_buf] has to be 76 * The maximum alignment that has been seen so far. If [_buf] has to be
72 * reallocated in the future (to insert room at its start for more bytes) the 77 * reallocated in the future (to insert room at its start for more bytes) the
73 * reallocation will need to be a multiple of this many bytes. 78 * reallocation will need to be a multiple of this many bytes.
74 */ 79 */
75 int _maxAlign; 80 int _maxAlign;
76 81
77 /** 82 /**
78 * The number of bytes that have been written to the buffer so far. The 83 * The number of bytes that have been written to the buffer so far. The
79 * most recently written byte is this many bytes from the end of [_buf]. 84 * most recently written byte is this many bytes from the end of [_buf].
80 */ 85 */
81 int _tail; 86 int _tail;
82 87
83 /** 88 /**
84 * The location of the end of the current table, measured in bytes from the 89 * The location of the end of the current table, measured in bytes from the
85 * end of [_buf], or `null` if a table is not currently being built. 90 * end of [_buf], or `null` if a table is not currently being built.
86 */ 91 */
87 int _currentTableEndTail; 92 int _currentTableEndTail;
88 93
89 _VTableBuilder _currentVTableBuilder; 94 _VTable _currentVTable;
90 95
91 Builder({this.initialSize: 1024}) { 96 Builder({this.initialSize: 1024}) {
92 reset(); 97 reset();
93 } 98 }
94 99
95 /** 100 /**
96 * Add the [field] with the given 32-bit signed integer [value]. The field is 101 * Add the [field] with the given 32-bit signed integer [value]. The field is
97 * not added if the [value] is equal to [def]. 102 * not added if the [value] is equal to [def].
98 */ 103 */
99 void addInt32(int field, int value, [int def]) { 104 void addInt32(int field, int value, [int def]) {
100 if (_currentVTableBuilder == null) { 105 if (_currentVTable == null) {
101 throw new StateError('Start a table before adding values.'); 106 throw new StateError('Start a table before adding values.');
102 } 107 }
103 if (value != def) { 108 if (value != def) {
104 int size = 4; 109 int size = 4;
105 _prepare(size, 1); 110 _prepare(size, 1);
106 _trackField(field); 111 _trackField(field);
107 _setInt32AtTail(_buf, _tail, value); 112 _setInt32AtTail(_buf, _tail, value);
108 } 113 }
109 } 114 }
110 115
111 /** 116 /**
112 * Add the [field] with the given 8-bit signed integer [value]. The field is 117 * Add the [field] with the given 8-bit signed integer [value]. The field is
113 * not added if the [value] is equal to [def]. 118 * not added if the [value] is equal to [def].
114 */ 119 */
115 void addInt8(int field, int value, [int def]) { 120 void addInt8(int field, int value, [int def]) {
116 if (_currentVTableBuilder == null) { 121 if (_currentVTable == null) {
117 throw new StateError('Start a table before adding values.'); 122 throw new StateError('Start a table before adding values.');
118 } 123 }
119 if (value != def) { 124 if (value != def) {
120 int size = 1; 125 int size = 1;
121 _prepare(size, 1); 126 _prepare(size, 1);
122 _trackField(field); 127 _trackField(field);
123 _buf.setInt8(_buf.lengthInBytes - _tail, value); 128 _buf.setInt8(_buf.lengthInBytes - _tail, value);
124 } 129 }
125 } 130 }
126 131
127 /** 132 /**
128 * Add the [field] referencing an object with the given [offset]. 133 * Add the [field] referencing an object with the given [offset].
129 */ 134 */
130 void addOffset(int field, Offset offset) { 135 void addOffset(int field, Offset offset) {
131 if (_currentVTableBuilder == null) { 136 if (_currentVTable == null) {
132 throw new StateError('Start a table before adding values.'); 137 throw new StateError('Start a table before adding values.');
133 } 138 }
134 if (offset != null) { 139 if (offset != null) {
135 _prepare(4, 1); 140 _prepare(4, 1);
136 _trackField(field); 141 _trackField(field);
137 _setUint32AtTail(_buf, _tail, _tail - offset._tail); 142 _setUint32AtTail(_buf, _tail, _tail - offset._tail);
138 } 143 }
139 } 144 }
140 145
141 /** 146 /**
142 * End the current table and return its offset. 147 * End the current table and return its offset.
143 */ 148 */
144 Offset endTable() { 149 Offset endTable() {
145 if (_currentVTableBuilder == null) { 150 if (_currentVTable == null) {
146 throw new StateError('Start a table before ending it.'); 151 throw new StateError('Start a table before ending it.');
147 } 152 }
148 // Prepare the size of the current table. 153 // Prepare the size of the current table.
149 int tableSize = _tail - _currentTableEndTail; 154 _currentVTable.tableSize = _tail - _currentTableEndTail;
150 // Prepare for writing the VTable. 155 // Prepare for writing the VTable.
151 _prepare(4, 1); 156 _prepare(4, 1);
152 int tableTail = _tail; 157 int tableTail = _tail;
153 // Write the VTable. 158 // Prepare the VTable to use for the current table.
154 // TODO(scheglov) implement VTable(s) sharing 159 int vTableTail;
155 _prepare(2, _currentVTableBuilder.numOfUint16); 160 {
156 _currentVTableBuilder.output( 161 _currentVTable.computeFieldOffsets(tableTail);
157 _buf, _buf.lengthInBytes - _tail, tableTail, tableSize); 162 // Try to find an existing compatible VTable.
163 for (_VTable vTable in _vTables) {
Paul Berry 2016/01/08 18:31:35 If this linear search proves too expensive, I have
164 if (_currentVTable.canUseExistingVTable(vTable)) {
165 vTableTail = vTable.tail;
166 }
167 }
168 // Write a new VTable.
169 if (vTableTail == null) {
170 _prepare(2, _currentVTable.numOfUint16);
171 vTableTail = _tail;
172 _currentVTable.tail = vTableTail;
173 _currentVTable.output(_buf, _buf.lengthInBytes - _tail);
174 _vTables.add(_currentVTable);
175 }
176 }
158 // Set the VTable offset. 177 // Set the VTable offset.
159 _setInt32AtTail(_buf, tableTail, _tail - tableTail); 178 _setInt32AtTail(_buf, tableTail, vTableTail - tableTail);
160 // Done with this table. 179 // Done with this table.
161 _currentVTableBuilder = null; 180 _currentVTable = null;
162 return new Offset(tableTail); 181 return new Offset(tableTail);
163 } 182 }
164 183
165 /** 184 /**
166 * Finish off the creation of the buffer. The given [offset] is used as the 185 * Finish off the creation of the buffer. The given [offset] is used as the
167 * root object offset, and usually references directly or indirectly every 186 * root object offset, and usually references directly or indirectly every
168 * written object. 187 * written object.
169 */ 188 */
170 Uint8List finish(Offset offset) { 189 Uint8List finish(Offset offset) {
171 _prepare(4, 1); 190 _prepare(4, 1);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 _buf.setUint8(_buf.lengthInBytes - _tail, value); 226 _buf.setUint8(_buf.lengthInBytes - _tail, value);
208 } 227 }
209 228
210 /** 229 /**
211 * Reset the builder and make it ready for filling a new buffer. 230 * Reset the builder and make it ready for filling a new buffer.
212 */ 231 */
213 void reset() { 232 void reset() {
214 _buf = new ByteData(initialSize); 233 _buf = new ByteData(initialSize);
215 _maxAlign = 1; 234 _maxAlign = 1;
216 _tail = 0; 235 _tail = 0;
217 _currentVTableBuilder = null; 236 _currentVTable = null;
218 } 237 }
219 238
220 /** 239 /**
221 * Start a new table. Must be finished with [endTable] invocation. 240 * Start a new table. Must be finished with [endTable] invocation.
222 */ 241 */
223 void startTable() { 242 void startTable() {
224 if (_currentVTableBuilder != null) { 243 if (_currentVTable != null) {
225 throw new StateError('Inline tables are not supported.'); 244 throw new StateError('Inline tables are not supported.');
226 } 245 }
227 _currentVTableBuilder = new _VTableBuilder(); 246 _currentVTable = new _VTable();
228 _currentTableEndTail = _tail; 247 _currentTableEndTail = _tail;
229 } 248 }
230 249
231 /** 250 /**
232 * Write the given list of [values]. 251 * Write the given list of [values].
233 */ 252 */
234 Offset writeList(List<Offset> values) { 253 Offset writeList(List<Offset> values) {
235 if (_currentVTableBuilder != null) { 254 if (_currentVTable != null) {
236 throw new StateError( 255 throw new StateError(
237 'Cannot write a non-scalar value while writing a table.'); 256 'Cannot write a non-scalar value while writing a table.');
238 } 257 }
239 _prepare(4, 1 + values.length); 258 _prepare(4, 1 + values.length);
240 Offset result = new Offset(_tail); 259 Offset result = new Offset(_tail);
241 int tail = _tail; 260 int tail = _tail;
242 _setUint32AtTail(_buf, tail, values.length); 261 _setUint32AtTail(_buf, tail, values.length);
243 tail -= 4; 262 tail -= 4;
244 for (Offset value in values) { 263 for (Offset value in values) {
245 _setUint32AtTail(_buf, tail, tail - value._tail); 264 _setUint32AtTail(_buf, tail, tail - value._tail);
246 tail -= 4; 265 tail -= 4;
247 } 266 }
248 return result; 267 return result;
249 } 268 }
250 269
251 /** 270 /**
252 * Write the given string [value] and return its [Offset], or `null` if 271 * Write the given string [value] and return its [Offset], or `null` if
253 * the [value] is equal to [def]. 272 * the [value] is equal to [def].
254 */ 273 */
255 Offset<String> writeString(String value, [String def]) { 274 Offset<String> writeString(String value, [String def]) {
256 if (_currentVTableBuilder != null) { 275 if (_currentVTable != null) {
257 throw new StateError( 276 throw new StateError(
258 'Cannot write a non-scalar value while writing a table.'); 277 'Cannot write a non-scalar value while writing a table.');
259 } 278 }
260 if (value != def) { 279 if (value != def) {
261 // TODO(scheglov) optimize for ASCII strings 280 // TODO(scheglov) optimize for ASCII strings
262 List<int> bytes = UTF8.encode(value); 281 List<int> bytes = UTF8.encode(value);
263 int length = bytes.length; 282 int length = bytes.length;
264 _prepare(4, 1, additionalBytes: length); 283 _prepare(4, 1, additionalBytes: length);
265 Offset<String> result = new Offset(_tail); 284 Offset<String> result = new Offset(_tail);
266 _setUint32AtTail(_buf, _tail, length); 285 _setUint32AtTail(_buf, _tail, length);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 } 322 }
304 } 323 }
305 // Update the tail pointer. 324 // Update the tail pointer.
306 _tail += bufSize; 325 _tail += bufSize;
307 } 326 }
308 327
309 /** 328 /**
310 * Record the offset of the given [field]. 329 * Record the offset of the given [field].
311 */ 330 */
312 void _trackField(int field) { 331 void _trackField(int field) {
313 _currentVTableBuilder.addField(field, _tail); 332 _currentVTable.addField(field, _tail);
314 } 333 }
315 334
316 static void _setInt32AtTail(ByteData _buf, int tail, int x) { 335 static void _setInt32AtTail(ByteData _buf, int tail, int x) {
317 _buf.setInt32(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN); 336 _buf.setInt32(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
318 } 337 }
319 338
320 static void _setUint32AtTail(ByteData _buf, int tail, int x) { 339 static void _setUint32AtTail(ByteData _buf, int tail, int x) {
321 _buf.setUint32(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN); 340 _buf.setUint32(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
322 } 341 }
323 } 342 }
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 BufferPointer ref = bp._advance(4 + elementReader.size * i); 486 BufferPointer ref = bp._advance(4 + elementReader.size * i);
468 return elementReader.read(ref); 487 return elementReader.read(ref);
469 } 488 }
470 489
471 @override 490 @override
472 void operator []=(int i, E e) => 491 void operator []=(int i, E e) =>
473 throw new StateError('Attempt to modify immutable list'); 492 throw new StateError('Attempt to modify immutable list');
474 } 493 }
475 494
476 /** 495 /**
477 * Class for building VTable(s). 496 * Class that describes the structure of a table.
478 */ 497 */
479 class _VTableBuilder { 498 class _VTable {
480 final List<int> fieldTails = <int>[]; 499 final List<int> fieldTails = <int>[];
500 final List<int> fieldOffsets = <int>[];
501
502 /**
503 * The size of the table that uses this VTable.
504 */
505 int tableSize;
506
507 /**
508 * The tail of this VTable. It is used to share the same VTable between
509 * multiple tables of identical structure.
510 */
511 int tail;
481 512
482 int get numOfUint16 => 1 + 1 + fieldTails.length; 513 int get numOfUint16 => 1 + 1 + fieldTails.length;
483 514
484 void addField(int field, int offset) { 515 void addField(int field, int offset) {
485 while (fieldTails.length <= field) { 516 while (fieldTails.length <= field) {
486 fieldTails.add(null); 517 fieldTails.add(null);
487 } 518 }
488 fieldTails[field] = offset; 519 fieldTails[field] = offset;
489 } 520 }
490 521
491 /** 522 /**
523 * Return `true` if the [existing] VTable can be used instead of this.
524 */
525 bool canUseExistingVTable(_VTable existing) {
526 assert(tail == null);
527 assert(existing.tail != null);
528 if (tableSize == existing.tableSize &&
529 fieldOffsets.length == existing.fieldOffsets.length) {
530 for (int i = 0; i < fieldOffsets.length; i++) {
531 if (fieldOffsets[i] != existing.fieldOffsets[i]) {
532 return false;
533 }
534 }
535 return true;
536 }
537 return false;
538 }
539
540 /**
541 * Fill the [fieldOffsets] field.
542 */
543 void computeFieldOffsets(int tableTail) {
544 assert(fieldOffsets.isEmpty);
545 for (int fieldTail in fieldTails) {
546 int fieldOffset = fieldTail == null ? 0 : tableTail - fieldTail;
547 fieldOffsets.add(fieldOffset);
548 }
549 }
550
551 /**
492 * Outputs this VTable to [buf], which is is expected to be aligned to 16-bit 552 * Outputs this VTable to [buf], which is is expected to be aligned to 16-bit
493 * and have at least [numOfUint16] 16-bit words available. 553 * and have at least [numOfUint16] 16-bit words available.
494 */ 554 */
495 void output(ByteData buf, int bufOffset, int tableTail, int tableSize) { 555 void output(ByteData buf, int bufOffset) {
496 // VTable size. 556 // VTable size.
497 buf.setUint16(bufOffset, numOfUint16 * 2, Endianness.LITTLE_ENDIAN); 557 buf.setUint16(bufOffset, numOfUint16 * 2, Endianness.LITTLE_ENDIAN);
498 bufOffset += 2; 558 bufOffset += 2;
499 // Table size. 559 // Table size.
500 buf.setUint16(bufOffset, tableSize, Endianness.LITTLE_ENDIAN); 560 buf.setUint16(bufOffset, tableSize, Endianness.LITTLE_ENDIAN);
501 bufOffset += 2; 561 bufOffset += 2;
502 // Field offsets. 562 // Field offsets.
503 for (int fieldTail in fieldTails) { 563 for (int fieldOffset in fieldOffsets) {
504 int fieldOffset = fieldTail == null ? 0 : tableTail - fieldTail;
505 buf.setUint16(bufOffset, fieldOffset, Endianness.LITTLE_ENDIAN); 564 buf.setUint16(bufOffset, fieldOffset, Endianness.LITTLE_ENDIAN);
506 bufOffset += 2; 565 bufOffset += 2;
507 } 566 }
508 } 567 }
509 } 568 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698