| 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.md file. | |
| 4 | |
| 5 library service.struct; | |
| 6 | |
| 7 import "dart:dartino.ffi"; | |
| 8 import "dart:collection"; | |
| 9 | |
| 10 const int HEADER_SIZE = 56; | |
| 11 | |
| 12 Reader getRoot(Reader reader, ForeignMemory request) { | |
| 13 int segments = request.getInt32(HEADER_SIZE - 8); | |
| 14 if (segments == 0) { | |
| 15 MessageReader messageReader = new MessageReader(); | |
| 16 Segment segment = new Segment(messageReader, request); | |
| 17 messageReader.segments.add(segment); | |
| 18 reader.$segment = segment; | |
| 19 reader.$offset = HEADER_SIZE; | |
| 20 return reader; | |
| 21 } else { | |
| 22 return getSegmentedRoot(reader, request, segments); | |
| 23 } | |
| 24 } | |
| 25 | |
| 26 Reader getSegmentedRoot(Reader reader, ForeignMemory request, int segments) { | |
| 27 MessageReader messageReader = new MessageReader(); | |
| 28 int offset = HEADER_SIZE + 8; | |
| 29 for (int i = 0; i < segments; i++) { | |
| 30 int address = (Foreign.bitsPerMachineWord == 32) | |
| 31 ? request.getUint32(offset) | |
| 32 : request.getUint64(offset); | |
| 33 int size = request.getInt32(offset + 8); | |
| 34 ForeignMemory memory = new ForeignMemory.fromAddress(address, size); | |
| 35 Segment segment = new Segment(messageReader, memory); | |
| 36 messageReader.segments.add(segment); | |
| 37 offset += 16; | |
| 38 } | |
| 39 reader.$segment = messageReader.segments.first; | |
| 40 reader.$offset = HEADER_SIZE; | |
| 41 return reader; | |
| 42 } | |
| 43 | |
| 44 int getResultMessage(Builder builder) { | |
| 45 BuilderSegment segment = builder.$segment; | |
| 46 if (segment._next == null) { | |
| 47 // Mark result as being non-segmented. | |
| 48 ForeignMemory memory = segment.memory; | |
| 49 memory.setInt32(0, 0); | |
| 50 memory.setInt32(4, memory.length); | |
| 51 return memory.address; | |
| 52 } | |
| 53 | |
| 54 // The result is a segmented message. Build a memory block that | |
| 55 // contains the addresses and sizes of all of them. | |
| 56 int segments = segment._builder.$segments; | |
| 57 int size = 8 + (segments * 16); | |
| 58 ForeignMemory buffer = new ForeignMemory.allocated(size); | |
| 59 // Mark the result as being segmented. | |
| 60 buffer.setInt32(0, segments); | |
| 61 int offset = 8; | |
| 62 do { | |
| 63 buffer.setInt64(offset, segment.memory.address); | |
| 64 buffer.setInt32(offset + 8, segment._used); | |
| 65 segment = segment._next; | |
| 66 offset += 16; | |
| 67 } while (segment != null); | |
| 68 return buffer.address; | |
| 69 } | |
| 70 | |
| 71 class MessageReader { | |
| 72 final List<Segment> segments = []; | |
| 73 MessageReader(); | |
| 74 | |
| 75 Segment getSegment(int id) => segments[id]; | |
| 76 } | |
| 77 | |
| 78 class Segment { | |
| 79 final MessageReader reader; | |
| 80 final ForeignMemory memory; | |
| 81 Segment(this.reader, this.memory); | |
| 82 } | |
| 83 | |
| 84 class Reader { | |
| 85 Segment $segment; | |
| 86 int $offset; | |
| 87 | |
| 88 readStruct(Reader reader, int offset) { | |
| 89 Segment segment = $segment; | |
| 90 offset += $offset; | |
| 91 while (true) { | |
| 92 ForeignMemory memory = segment.memory; | |
| 93 int lo = memory.getInt32($offset + 0); | |
| 94 int hi = memory.getInt32($offset + 4); | |
| 95 int tag = lo & 3; | |
| 96 if (tag == 0) { | |
| 97 throw new UnimplementedError("Cannot read uninitialized structs"); | |
| 98 } else if (tag == 1) { | |
| 99 reader.$segment = segment; | |
| 100 reader.$offset = lo >> 2; | |
| 101 return reader; | |
| 102 } else { | |
| 103 segment = segment.reader.getSegment(hi); | |
| 104 $offset = lo >> 2; | |
| 105 } | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 readList(ListReader reader, int offset) { | |
| 110 Segment segment = $segment; | |
| 111 offset += $offset; | |
| 112 while (true) { | |
| 113 ForeignMemory memory = segment.memory; | |
| 114 int lo = memory.getInt32(offset + 0); | |
| 115 int hi = memory.getInt32(offset + 4); | |
| 116 int tag = lo & 3; | |
| 117 if (tag == 0) { | |
| 118 // If the list hasn't been initialized, then | |
| 119 // we return an empty list. | |
| 120 reader.$length = 0; | |
| 121 return reader; | |
| 122 } else if (tag == 2) { | |
| 123 reader.$segment = segment; | |
| 124 reader.$offset = lo >> 2; | |
| 125 reader.$length = hi; | |
| 126 return reader; | |
| 127 } else { | |
| 128 segment = segment.reader.getSegment(hi); | |
| 129 offset = lo >> 2; | |
| 130 } | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 String readString(ListReader reader, int offset) { | |
| 135 List<int> charCodes = readList(reader, offset); | |
| 136 return new String.fromCharCodes(charCodes); | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 abstract class ListReader<T> extends Reader with ListMixin<T> { | |
| 141 int $length; | |
| 142 int get length => $length; // Required by List<T>. | |
| 143 | |
| 144 readListElement(Reader reader, int index, int size) { | |
| 145 reader.$segment = $segment; | |
| 146 reader.$offset = $offset + index * size; | |
| 147 return reader; | |
| 148 } | |
| 149 | |
| 150 void operator []=(int index, value) { | |
| 151 throw new UnsupportedError("ListReader::operator []="); | |
| 152 } | |
| 153 | |
| 154 void set length(int newLength) { | |
| 155 throw new UnsupportedError("ListReader::set length"); | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 class BuilderSegment { | |
| 160 final MessageBuilder _builder; | |
| 161 final ForeignMemory memory; | |
| 162 int _id; | |
| 163 int _used = 0; | |
| 164 BuilderSegment _next; | |
| 165 | |
| 166 BuilderSegment(this._builder, this._id, int space) | |
| 167 : memory = new ForeignMemory.allocated(space); | |
| 168 | |
| 169 bool HasSpaceForBytes(int bytes) => _used + bytes <= memory.length; | |
| 170 | |
| 171 int Allocate(int bytes) { | |
| 172 if (!HasSpaceForBytes(bytes)) return -1; | |
| 173 var result = _used; | |
| 174 _used += bytes; | |
| 175 return result; | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 class MessageBuilder { | |
| 180 BuilderSegment _first; | |
| 181 BuilderSegment _last; | |
| 182 int $segments = 1; | |
| 183 | |
| 184 MessageBuilder(int space) { | |
| 185 _first = new BuilderSegment(this, 0, space); | |
| 186 _last = _first; | |
| 187 } | |
| 188 | |
| 189 Builder initRoot(Builder builder, int size) { | |
| 190 int offset = _first.Allocate(8 + size); | |
| 191 builder.$segment = _first; | |
| 192 builder.$offset = offset + 8; | |
| 193 return builder; | |
| 194 } | |
| 195 | |
| 196 BuilderSegment FindSegmentForBytes(int bytes) { | |
| 197 if (_last.HasSpaceForBytes(bytes)) return _last; | |
| 198 int capacity = (bytes > 8192) ? bytes : 8192; | |
| 199 BuilderSegment segment = new BuilderSegment(this, $segments++, capacity); | |
| 200 _last._next = segment; | |
| 201 _last = segment; | |
| 202 return segment; | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 class Builder { | |
| 207 BuilderSegment $segment; | |
| 208 int $offset; | |
| 209 | |
| 210 Builder NewStruct(Builder builder, int offset, int size) { | |
| 211 offset += $offset; | |
| 212 BuilderSegment segment = $segment; | |
| 213 while (true) { | |
| 214 int result = segment.Allocate(size); | |
| 215 ForeignMemory memory = segment.memory; | |
| 216 if (result >= 0) { | |
| 217 memory.setInt32(offset + 0, (result << 2) | 1); | |
| 218 memory.setInt32(offset + 4, 0); | |
| 219 builder.$segment = segment; | |
| 220 builder.$offset = result; | |
| 221 return builder; | |
| 222 } | |
| 223 | |
| 224 BuilderSegment other = segment._builder.FindSegmentForBytes(size + 8); | |
| 225 int target = other.Allocate(8); | |
| 226 memory.setInt32(offset + 0, (target << 2) | 3); | |
| 227 memory.setInt32(offset + 4, other._id); | |
| 228 | |
| 229 segment = other; | |
| 230 offset = target; | |
| 231 } | |
| 232 } | |
| 233 | |
| 234 ListBuilder NewList(ListBuilder list, | |
| 235 int offset, | |
| 236 int length, | |
| 237 int size) { | |
| 238 list.$length = length; | |
| 239 offset += $offset; | |
| 240 size *= length; | |
| 241 BuilderSegment segment = $segment; | |
| 242 while (true) { | |
| 243 int result = segment.Allocate(size); | |
| 244 ForeignMemory memory = segment.memory; | |
| 245 if (result >= 0) { | |
| 246 memory.setInt32(offset + 0, (result << 2) | 1); | |
| 247 memory.setInt32(offset + 4, length); | |
| 248 list.$segment = segment; | |
| 249 list.$offset = result; | |
| 250 return list; | |
| 251 } | |
| 252 | |
| 253 BuilderSegment other = segment._builder.FindSegmentForBytes(size + 8); | |
| 254 int target = other.Allocate(8); | |
| 255 memory.setInt32(offset + 0, (target << 2) | 3); | |
| 256 memory.setInt32(offset + 4, other._id); | |
| 257 | |
| 258 segment = other; | |
| 259 offset = target; | |
| 260 } | |
| 261 } | |
| 262 | |
| 263 void NewString(ListBuilder list, int offset, String value) { | |
| 264 NewList(list, offset, value.length, 2); | |
| 265 for (int i = 0; i < value.length; i++) { | |
| 266 list[i] = value.codeUnitAt(i); | |
| 267 } | |
| 268 } | |
| 269 } | |
| 270 | |
| 271 abstract class ListBuilder<T> extends Builder with ListMixin<T> { | |
| 272 int $length; | |
| 273 int get length => $length; | |
| 274 | |
| 275 readListElement(Builder builder, int index, int size) { | |
| 276 builder.$segment = $segment; | |
| 277 builder.$offset = $offset + index * size; | |
| 278 return builder; | |
| 279 } | |
| 280 | |
| 281 void operator []=(int index, value) { | |
| 282 throw new UnsupportedError("ListBuilder::operator []="); | |
| 283 } | |
| 284 | |
| 285 void set length(int newLength) { | |
| 286 throw new UnsupportedError("ListBuilder::set length"); | |
| 287 } | |
| 288 } | |
| OLD | NEW |