OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
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. | |
4 | |
5 library old_servicec.struct_builder; | |
6 | |
7 import 'parser.dart'; | |
8 import 'primitives.dart' as primitives; | |
9 | |
10 import 'dart:collection'; | |
11 import 'dart:core' hide Type; | |
12 import 'dart:math' show max; | |
13 | |
14 const int POINTER_SIZE = 8; | |
15 | |
16 int _roundUp(int n, int alignment) { | |
17 return (n + alignment - 1) & ~(alignment - 1); | |
18 } | |
19 | |
20 class StructLayout { | |
21 final Map<String, StructSlot> _slots; | |
22 final int size; | |
23 final List<_StructHole> _holes; | |
24 StructLayout._(this._slots, this.size, this._holes); | |
25 | |
26 factory StructLayout(Struct struct) { | |
27 _StructBuilder builder = new _StructBuilder(); | |
28 | |
29 struct.slots.forEach(builder.addSlot); | |
30 if (struct.unions.isNotEmpty) { | |
31 builder.addUnionSlots(struct.unions.single); | |
32 } | |
33 return builder.finalize(0); | |
34 } | |
35 | |
36 factory StructLayout.forArguments(List<Formal> arguments) { | |
37 _StructBuilder builder = new _StructBuilder(); | |
38 arguments.forEach(builder.addSlot); | |
39 return builder.finalize(POINTER_SIZE); | |
40 } | |
41 | |
42 Iterable<StructSlot> get slots => _slots.values; | |
43 StructSlot operator[](Formal slot) => _slots[slot.name]; | |
44 } | |
45 | |
46 class StructSlot { | |
47 final Formal slot; | |
48 final int offset; | |
49 final int size; | |
50 | |
51 final Union union; | |
52 final int unionTag; | |
53 | |
54 StructSlot(this.slot, this.offset, this.size, this.union, this.unionTag); | |
55 | |
56 bool get isUnionSlot => union != null; | |
57 } | |
58 | |
59 class _StructRegion { | |
60 final int size; | |
61 final int alignment; | |
62 | |
63 final bool isUnion; | |
64 final owner; | |
65 | |
66 _StructRegion.forSlot(this.size, this.alignment, Formal this.owner) | |
67 : isUnion = false; | |
68 | |
69 _StructRegion.forUnion(this.size, this.alignment, Union this.owner) | |
70 : isUnion = true; | |
71 | |
72 Formal get slot { | |
73 assert(!isUnion); | |
74 return owner; | |
75 } | |
76 | |
77 Union get union { | |
78 assert(isUnion); | |
79 return owner; | |
80 } | |
81 } | |
82 | |
83 class _StructHole extends LinkedListEntry { | |
84 int begin; | |
85 int end; | |
86 _StructHole(this.begin, this.end); | |
87 | |
88 int get size => end - begin; | |
89 } | |
90 | |
91 class _StructBuilder { | |
92 final List<_StructRegion> regions = <_StructRegion>[]; | |
93 final Map<String, StructSlot> slots = new LinkedHashMap<String, StructSlot>(); | |
94 final LinkedList<_StructHole> holes = new LinkedList<_StructHole>(); | |
95 int used = 0; | |
96 | |
97 StructLayout finalize(int minimum) { | |
98 // Sort the regions by size, so we get the largest regions first. | |
99 regions.sort((x, y) => y.size - x.size); | |
100 | |
101 for (_StructRegion region in regions) { | |
102 int offset = allocate(region.size, region.alignment); | |
103 if (region.isUnion) { | |
104 Union union = region.union; | |
105 int tag = 1; | |
106 union.slots.forEach((Formal slot) { | |
107 _defineSlot(slot, offset, computeSize(slot.type), union, tag++); | |
108 }); | |
109 } else { | |
110 _defineSlot(region.slot, offset, region.size, null, -1); | |
111 } | |
112 } | |
113 | |
114 int size = max(allocate(0, POINTER_SIZE), minimum); | |
115 return new StructLayout._(slots, size, holes.toList()); | |
116 } | |
117 | |
118 int allocate(int size, int alignment) { | |
119 int result = _allocateFromHole(size, alignment); | |
120 if (result >= 0) return result; | |
121 | |
122 result = _roundUp(used, alignment); | |
123 int padding = result - used; | |
124 if (padding > 0) { | |
125 holes.add(new _StructHole(result - padding, result)); | |
126 } | |
127 used = result + size; | |
128 return result; | |
129 } | |
130 | |
131 int _allocateFromHole(int size, int alignment) { | |
132 if (size == 0) return -1; | |
133 for (_StructHole hole in holes) { | |
134 int offset = _roundUp(hole.begin, alignment); | |
135 if (offset + size <= hole.end) { | |
136 _splitHole(hole, offset, size); | |
137 return offset; | |
138 } | |
139 } | |
140 return -1; | |
141 } | |
142 | |
143 void _splitHole(_StructHole hole, int offset, int size) { | |
144 int end = hole.end; | |
145 if (offset + size < end) { | |
146 // Insert hole after. | |
147 hole.insertAfter(new _StructHole(offset + size, end)); | |
148 } | |
149 // Shrink the hole before. | |
150 hole.end = offset; | |
151 if (hole.size == 0) holes.remove(hole); | |
152 } | |
153 | |
154 void addSlot(Formal slot) { | |
155 Type type = slot.type; | |
156 int size = computeSize(type); | |
157 int alignment = computeAlignment(type); | |
158 regions.add(new _StructRegion.forSlot(size, alignment, slot)); | |
159 } | |
160 | |
161 void addUnionSlots(Union union) { | |
162 List<Formal> unionSlots = union.slots; | |
163 if (unionSlots.isEmpty) return; | |
164 | |
165 int unionSize = 0; | |
166 int unionAlignment = 0; | |
167 unionSlots.forEach((Formal slot) { | |
168 Type type = slot.type; | |
169 int size = computeSize(type); | |
170 if (size > unionSize) unionSize = size; | |
171 int alignment = computeAlignment(type); | |
172 if (alignment > unionAlignment) unionAlignment = alignment; | |
173 }); | |
174 | |
175 regions.add(new _StructRegion.forUnion(unionSize, unionAlignment, union)); | |
176 } | |
177 | |
178 void _defineSlot(Formal slot, int offset, int size, Union union, int tag) { | |
179 String name = slot.name; | |
180 if (slots.containsKey(name)) { | |
181 throw new UnsupportedError("Duplicate slot '$name' in struct."); | |
182 } | |
183 slots[name] = new StructSlot(slot, offset, size, union, tag); | |
184 } | |
185 | |
186 int computeSize(Type type) { | |
187 if (type.isPointer || type.isList || type.isString) return POINTER_SIZE; | |
188 if (type.isPrimitive) return primitives.size(type.primitiveType); | |
189 | |
190 Struct struct = type.resolved; | |
191 StructLayout layout = struct.layout; | |
192 for (_StructHole hole in layout._holes) { | |
193 holes.add(new _StructHole(hole.begin, hole.end)); | |
194 } | |
195 return _roundUp(layout.size, POINTER_SIZE); | |
196 } | |
197 | |
198 int computeAlignment(Type type) { | |
199 return (type.isPrimitive && !type.isList && !type.isString) | |
200 ? primitives.size(type.primitiveType) | |
201 : POINTER_SIZE; | |
202 } | |
203 } | |
OLD | NEW |