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