| 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 fletchc.fletch_system_builder; | |
| 6 | |
| 7 import 'dart:typed_data'; | |
| 8 | |
| 9 import 'package:compiler/src/constants/values.dart' show | |
| 10 ConstantValue, | |
| 11 ConstructedConstantValue, | |
| 12 DeferredConstantValue, | |
| 13 FunctionConstantValue, | |
| 14 IntConstantValue, | |
| 15 ListConstantValue, | |
| 16 MapConstantValue, | |
| 17 StringConstantValue; | |
| 18 | |
| 19 import 'package:compiler/src/elements/elements.dart' show | |
| 20 ClassElement, | |
| 21 ConstructorElement, | |
| 22 Element, | |
| 23 FieldElement, | |
| 24 FunctionElement, | |
| 25 FunctionSignature, | |
| 26 MemberElement; | |
| 27 | |
| 28 import 'package:compiler/src/universe/call_structure.dart' show | |
| 29 CallStructure; | |
| 30 | |
| 31 import 'package:persistent/persistent.dart' show | |
| 32 PersistentMap; | |
| 33 | |
| 34 import 'fletch_constants.dart' show | |
| 35 FletchClassConstant, | |
| 36 FletchFunctionConstant, | |
| 37 FletchClassInstanceConstant; | |
| 38 | |
| 39 import 'fletch_class_builder.dart'; | |
| 40 import 'fletch_context.dart'; | |
| 41 import 'fletch_function_builder.dart'; | |
| 42 | |
| 43 import '../fletch_system.dart'; | |
| 44 import '../vm_commands.dart'; | |
| 45 | |
| 46 class FletchSystemBuilder { | |
| 47 final FletchSystem predecessorSystem; | |
| 48 final int functionIdStart; | |
| 49 final int classIdStart; | |
| 50 | |
| 51 final List<FletchFunctionBuilder> _newFunctions = <FletchFunctionBuilder>[]; | |
| 52 final Map<int, FletchClassBuilder> _newClasses = <int, FletchClassBuilder>{}; | |
| 53 final Map<ConstantValue, int> _newConstants = <ConstantValue, int>{}; | |
| 54 final Map<ParameterStubSignature, FletchFunctionBuilder> _newParameterStubs = | |
| 55 <ParameterStubSignature, FletchFunctionBuilder>{}; | |
| 56 | |
| 57 final Map<int, int> _newGettersByFieldIndex = <int, int>{}; | |
| 58 final Map<int, int> _newSettersByFieldIndex = <int, int>{}; | |
| 59 | |
| 60 final List<FletchFunction> _removedFunctions = <FletchFunction>[]; | |
| 61 | |
| 62 final Map<Element, FletchFunctionBuilder> _functionBuildersByElement = | |
| 63 <Element, FletchFunctionBuilder>{}; | |
| 64 | |
| 65 final Map<ClassElement, FletchClassBuilder> _classBuildersByElement = | |
| 66 <ClassElement, FletchClassBuilder>{}; | |
| 67 | |
| 68 final Map<ConstructorElement, FletchFunctionBuilder> | |
| 69 _newConstructorInitializers = | |
| 70 <ConstructorElement, FletchFunctionBuilder>{}; | |
| 71 | |
| 72 // TODO(ajohnsen): By function/class? | |
| 73 final Map<Element, List<FunctionElement>> _replaceUsage = | |
| 74 <Element, List<FunctionElement>>{}; | |
| 75 | |
| 76 final Map<int, int> _newTearoffsById = <int, int>{}; | |
| 77 | |
| 78 final int maxInt64 = (1 << 63) - 1; | |
| 79 final int minInt64 = -(1 << 63); | |
| 80 | |
| 81 final Map<int, String> _symbolByFletchSelectorId = <int, String>{}; | |
| 82 | |
| 83 FletchSystemBuilder(FletchSystem predecessorSystem) | |
| 84 : this.predecessorSystem = predecessorSystem, | |
| 85 this.functionIdStart = predecessorSystem.computeMaxFunctionId() + 1, | |
| 86 this.classIdStart = predecessorSystem.computeMaxClassId() + 1; | |
| 87 | |
| 88 int lookupConstantIdByValue(ConstantValue value) { | |
| 89 int id = _newConstants[value]; | |
| 90 if (id != null) return id; | |
| 91 FletchConstant constant = predecessorSystem.lookupConstantByValue(value); | |
| 92 return constant?.id; | |
| 93 } | |
| 94 | |
| 95 void replaceUsage(Element element, FunctionElement usage) { | |
| 96 _replaceUsage.putIfAbsent(element, () => []).add(usage); | |
| 97 } | |
| 98 | |
| 99 FletchFunctionBuilder newFunctionBuilder( | |
| 100 FletchFunctionKind kind, | |
| 101 int arity, | |
| 102 {String name, | |
| 103 Element element, | |
| 104 FunctionSignature signature, | |
| 105 int memberOf, | |
| 106 Element mapByElement}) { | |
| 107 int nextFunctionId = functionIdStart + _newFunctions.length; | |
| 108 FletchFunctionBuilder builder = new FletchFunctionBuilder( | |
| 109 nextFunctionId, | |
| 110 kind, | |
| 111 arity, | |
| 112 name: name, | |
| 113 element: element, | |
| 114 signature: signature, | |
| 115 memberOf: memberOf); | |
| 116 _newFunctions.add(builder); | |
| 117 if (mapByElement != null) { | |
| 118 _functionBuildersByElement[mapByElement] = builder; | |
| 119 } | |
| 120 return builder; | |
| 121 } | |
| 122 | |
| 123 FletchFunctionBuilder newFunctionBuilderWithSignature( | |
| 124 String name, | |
| 125 Element element, | |
| 126 FunctionSignature signature, | |
| 127 int memberOf, | |
| 128 {FletchFunctionKind kind: FletchFunctionKind.NORMAL, | |
| 129 Element mapByElement}) { | |
| 130 int arity = signature.parameterCount + (memberOf != null ? 1 : 0); | |
| 131 return newFunctionBuilder( | |
| 132 kind, | |
| 133 arity, | |
| 134 name: name, | |
| 135 element: element, | |
| 136 signature: signature, | |
| 137 memberOf: memberOf, | |
| 138 mapByElement: mapByElement); | |
| 139 } | |
| 140 | |
| 141 FletchFunctionBase lookupFunction(int functionId) { | |
| 142 if (functionId < functionIdStart) { | |
| 143 return predecessorSystem.lookupFunctionById(functionId); | |
| 144 } else { | |
| 145 return lookupFunctionBuilder(functionId); | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 FletchFunctionBuilder lookupFunctionBuilder(int functionId) { | |
| 150 return _newFunctions[functionId - functionIdStart]; | |
| 151 } | |
| 152 | |
| 153 FletchFunctionBase lookupFunctionByElement(Element element) { | |
| 154 FletchFunctionBase function = _functionBuildersByElement[element]; | |
| 155 if (function != null) return function; | |
| 156 return predecessorSystem.lookupFunctionByElement(element); | |
| 157 } | |
| 158 | |
| 159 FletchFunctionBuilder lookupFunctionBuilderByElement(Element element) { | |
| 160 return _functionBuildersByElement[element]; | |
| 161 } | |
| 162 | |
| 163 FletchFunctionBase lookupConstructorInitializerByElement( | |
| 164 ConstructorElement element) { | |
| 165 assert(element.isImplementation); | |
| 166 FletchFunctionBase function = _newConstructorInitializers[element]; | |
| 167 if (function != null) return function; | |
| 168 return predecessorSystem.lookupConstructorInitializerByElement(element); | |
| 169 } | |
| 170 | |
| 171 FletchFunctionBuilder newConstructorInitializer(ConstructorElement element) { | |
| 172 assert(element.isImplementation); | |
| 173 FletchFunctionBuilder builder = newFunctionBuilderWithSignature( | |
| 174 element.name, | |
| 175 element, | |
| 176 element.functionSignature, | |
| 177 null, | |
| 178 kind: FletchFunctionKind.INITIALIZER_LIST); | |
| 179 _newConstructorInitializers[element] = builder; | |
| 180 return builder; | |
| 181 } | |
| 182 | |
| 183 int lookupTearOffById(int functionId) { | |
| 184 int id = _newTearoffsById[functionId]; | |
| 185 if (id != null) return id; | |
| 186 return predecessorSystem.lookupTearOffById(functionId); | |
| 187 } | |
| 188 | |
| 189 FletchFunctionBuilder newTearOff(FletchFunctionBase function, int classId) { | |
| 190 FletchFunctionBuilder builder = newFunctionBuilderWithSignature( | |
| 191 'call', | |
| 192 null, | |
| 193 function.signature, | |
| 194 classId); | |
| 195 _newTearoffsById[function.functionId] = builder.functionId; | |
| 196 return builder; | |
| 197 } | |
| 198 | |
| 199 /// Return a getter for [fieldIndex] if it already exists, return null | |
| 200 /// otherwise. | |
| 201 int lookupGetterByFieldIndex(int fieldIndex) { | |
| 202 int functionId = _newGettersByFieldIndex[fieldIndex]; | |
| 203 if (functionId == null) { | |
| 204 return predecessorSystem.lookupGetterByFieldIndex(fieldIndex); | |
| 205 } | |
| 206 return functionId; | |
| 207 } | |
| 208 | |
| 209 /// Create a new getter for [fieldIndex]. | |
| 210 FletchFunctionBuilder newGetter(int fieldIndex) { | |
| 211 FletchFunctionBuilder builder = | |
| 212 newFunctionBuilder(FletchFunctionKind.ACCESSOR, 1); | |
| 213 _newGettersByFieldIndex[fieldIndex] = builder.functionId; | |
| 214 return builder; | |
| 215 } | |
| 216 | |
| 217 /// Return a getter for [fieldIndex]. If one doesn't already exists, one will | |
| 218 /// be created. | |
| 219 int getGetterByFieldIndex(int fieldIndex) { | |
| 220 int id = lookupGetterByFieldIndex(fieldIndex); | |
| 221 if (id != null) return id; | |
| 222 FletchFunctionBuilder stub = newGetter(fieldIndex); | |
| 223 stub.assembler | |
| 224 ..loadParameter(0) | |
| 225 ..loadField(fieldIndex) | |
| 226 ..ret() | |
| 227 ..methodEnd(); | |
| 228 return stub.functionId; | |
| 229 } | |
| 230 | |
| 231 /// Return a setter for [fieldIndex] if it already exists, return null | |
| 232 /// otherwise. | |
| 233 int lookupSetterByFieldIndex(int fieldIndex) { | |
| 234 int functionId = _newSettersByFieldIndex[fieldIndex]; | |
| 235 if (functionId == null) { | |
| 236 return predecessorSystem.lookupSetterByFieldIndex(fieldIndex); | |
| 237 } | |
| 238 return functionId; | |
| 239 } | |
| 240 | |
| 241 /// Create a new setter for [fieldIndex]. | |
| 242 FletchFunctionBuilder newSetter(int fieldIndex) { | |
| 243 FletchFunctionBuilder builder = | |
| 244 newFunctionBuilder(FletchFunctionKind.ACCESSOR, 2); | |
| 245 _newSettersByFieldIndex[fieldIndex] = builder.functionId; | |
| 246 return builder; | |
| 247 } | |
| 248 | |
| 249 /// Return a setter for [fieldIndex]. If one doesn't already exists, one will | |
| 250 /// be created. | |
| 251 int getSetterByFieldIndex(int fieldIndex) { | |
| 252 int id = lookupSetterByFieldIndex(fieldIndex); | |
| 253 if (id != null) return id; | |
| 254 FletchFunctionBuilder stub = newSetter(fieldIndex); | |
| 255 stub.assembler | |
| 256 ..loadParameter(0) | |
| 257 ..loadParameter(1) | |
| 258 ..storeField(fieldIndex) | |
| 259 // Top is at this point the rhs argument, thus the return value. | |
| 260 ..ret() | |
| 261 ..methodEnd(); | |
| 262 return stub.functionId; | |
| 263 } | |
| 264 | |
| 265 void forgetFunction(FletchFunction function) { | |
| 266 _removedFunctions.add(function); | |
| 267 } | |
| 268 | |
| 269 List<FletchFunctionBuilder> getNewFunctions() => _newFunctions; | |
| 270 | |
| 271 FletchClassBuilder getTearoffClassBuilder( | |
| 272 FletchFunctionBase function, | |
| 273 FletchClassBuilder superclass) { | |
| 274 int functionId = lookupTearOffById(function.functionId); | |
| 275 if (functionId == null) return null; | |
| 276 FletchFunctionBase functionBuilder = lookupFunction(functionId); | |
| 277 FletchClassBuilder classBuilder = | |
| 278 lookupClassBuilder(functionBuilder.memberOf); | |
| 279 if (classBuilder != null) return classBuilder; | |
| 280 FletchClass cls = lookupClass(functionBuilder.memberOf); | |
| 281 return newClassBuilderInternal(cls, superclass); | |
| 282 } | |
| 283 | |
| 284 FletchClassBuilder newClassBuilderInternal( | |
| 285 FletchClass klass, | |
| 286 FletchClassBuilder superclass) { | |
| 287 FletchClassBuilder builder = new FletchPatchClassBuilder( | |
| 288 klass, superclass); | |
| 289 assert(_newClasses[klass.classId] == null); | |
| 290 _newClasses[klass.classId] = builder; | |
| 291 return builder; | |
| 292 } | |
| 293 | |
| 294 FletchClassBuilder newPatchClassBuilder( | |
| 295 int classId, | |
| 296 FletchClassBuilder superclass) { | |
| 297 FletchClass klass = lookupClass(classId); | |
| 298 return newClassBuilderInternal(klass, superclass); | |
| 299 } | |
| 300 | |
| 301 FletchClassBuilder newClassBuilder( | |
| 302 ClassElement element, | |
| 303 FletchClassBuilder superclass, | |
| 304 bool isBuiltin, | |
| 305 {int extraFields: 0}) { | |
| 306 if (element != null) { | |
| 307 FletchClass klass = predecessorSystem.lookupClassByElement(element); | |
| 308 if (klass != null) { | |
| 309 FletchClassBuilder builder = newClassBuilderInternal(klass, superclass); | |
| 310 _classBuildersByElement[element] = builder; | |
| 311 return builder; | |
| 312 } | |
| 313 } | |
| 314 | |
| 315 int nextClassId = classIdStart + _newClasses.length; | |
| 316 FletchClassBuilder builder = new FletchNewClassBuilder( | |
| 317 nextClassId, | |
| 318 element, | |
| 319 superclass, | |
| 320 isBuiltin, | |
| 321 extraFields); | |
| 322 _newClasses[nextClassId] = builder; | |
| 323 if (element != null) _classBuildersByElement[element] = builder; | |
| 324 return builder; | |
| 325 } | |
| 326 | |
| 327 FletchClass lookupClass(int classId) { | |
| 328 return predecessorSystem.classesById[classId]; | |
| 329 } | |
| 330 | |
| 331 FletchClassBuilder lookupClassBuilder(int classId) { | |
| 332 return _newClasses[classId]; | |
| 333 } | |
| 334 | |
| 335 FletchClassBuilder lookupClassBuilderByElement(ClassElement element) { | |
| 336 return _classBuildersByElement[element]; | |
| 337 } | |
| 338 | |
| 339 Iterable<FletchClassBuilder> getNewClasses() => _newClasses.values; | |
| 340 | |
| 341 void registerConstant(ConstantValue constant, FletchContext context) { | |
| 342 if (predecessorSystem.lookupConstantByValue(constant) != null) return; | |
| 343 _newConstants.putIfAbsent(constant, () { | |
| 344 if (constant.isConstructedObject) { | |
| 345 context.registerConstructedConstantValue(constant); | |
| 346 } else if (constant.isFunction) { | |
| 347 context.registerFunctionConstantValue(constant); | |
| 348 } | |
| 349 for (ConstantValue value in constant.getDependencies()) { | |
| 350 registerConstant(value, context); | |
| 351 } | |
| 352 // TODO(zarah): Compute max constant id (as for functions an classes) | |
| 353 // instead of using constantsById.length | |
| 354 return predecessorSystem.constantsById.length + _newConstants.length; | |
| 355 }); | |
| 356 } | |
| 357 | |
| 358 void registerSymbol(String symbol, int fletchSelectorId) { | |
| 359 _symbolByFletchSelectorId[fletchSelectorId] = symbol; | |
| 360 } | |
| 361 | |
| 362 FletchFunctionBase lookupParameterStub(ParameterStubSignature signature) { | |
| 363 FletchFunctionBuilder stub = _newParameterStubs[signature]; | |
| 364 if (stub != null) return stub; | |
| 365 return predecessorSystem.lookupParameterStub(signature); | |
| 366 } | |
| 367 | |
| 368 void registerParameterStub( | |
| 369 ParameterStubSignature signature, | |
| 370 FletchFunctionBuilder stub) { | |
| 371 assert(lookupParameterStub(signature) == null); | |
| 372 _newParameterStubs[signature] = stub; | |
| 373 } | |
| 374 | |
| 375 FletchSystem computeSystem(FletchContext context, List<VmCommand> commands) { | |
| 376 // TODO(ajohnsen): Consider if the incremental compiler should be aware of | |
| 377 // callMain, when detecting changes. | |
| 378 FunctionElement callMain = | |
| 379 context.backend.fletchSystemLibrary.findLocal('callMain'); | |
| 380 replaceUsage(callMain, context.compiler.mainFunction); | |
| 381 | |
| 382 int changes = 0; | |
| 383 | |
| 384 // Remove all removed FletchFunctions. | |
| 385 for (FletchFunction function in _removedFunctions) { | |
| 386 commands.add(new RemoveFromMap(MapId.methods, function.functionId)); | |
| 387 } | |
| 388 | |
| 389 // Create all new FletchFunctions. | |
| 390 List<FletchFunction> functions = <FletchFunction>[]; | |
| 391 for (FletchFunctionBuilder builder in _newFunctions) { | |
| 392 context.compiler.reporter.withCurrentElement(builder.element, () { | |
| 393 functions.add(builder.finalizeFunction(context, commands)); | |
| 394 }); | |
| 395 } | |
| 396 | |
| 397 // Create all new FletchClasses. | |
| 398 List<FletchClass> classes = <FletchClass>[]; | |
| 399 for (FletchClassBuilder builder in _newClasses.values) { | |
| 400 classes.add(builder.finalizeClass(context, commands)); | |
| 401 changes++; | |
| 402 } | |
| 403 | |
| 404 // Create all statics. | |
| 405 // TODO(ajohnsen): Should be part of the fletch system. Does not work with | |
| 406 // incremental. | |
| 407 if (predecessorSystem.isEmpty) { | |
| 408 context.forEachStatic((element, index) { | |
| 409 FletchFunctionBuilder initializer = | |
| 410 context.backend.lazyFieldInitializers[element]; | |
| 411 if (initializer != null) { | |
| 412 commands.add(new PushFromMap(MapId.methods, initializer.functionId)); | |
| 413 commands.add(const PushNewInitializer()); | |
| 414 } else { | |
| 415 commands.add(const PushNull()); | |
| 416 } | |
| 417 }); | |
| 418 commands.add(new ChangeStatics(context.staticIndices.length)); | |
| 419 changes++; | |
| 420 } | |
| 421 | |
| 422 // Create all FletchConstants. | |
| 423 PersistentMap<int, FletchConstant> constantsById = | |
| 424 predecessorSystem.constantsById; | |
| 425 PersistentMap<ConstantValue, FletchConstant> constantsByValue = | |
| 426 predecessorSystem.constantsByValue; | |
| 427 _newConstants.forEach((constant, int id) { | |
| 428 void addList(List<ConstantValue> list, bool isByteList) { | |
| 429 for (ConstantValue entry in list) { | |
| 430 int entryId = lookupConstantIdByValue(entry); | |
| 431 commands.add(new PushFromMap(MapId.constants, entryId)); | |
| 432 if (entry.isInt) { | |
| 433 IntConstantValue constant = entry; | |
| 434 int value = constant.primitiveValue; | |
| 435 if (value & 0xFF == value) continue; | |
| 436 } | |
| 437 isByteList = false; | |
| 438 } | |
| 439 if (isByteList) { | |
| 440 // TODO(ajohnsen): The PushConstantByteList command could take a | |
| 441 // paylod with the data content. | |
| 442 commands.add(new PushConstantByteList(list.length)); | |
| 443 } else { | |
| 444 commands.add(new PushConstantList(list.length)); | |
| 445 } | |
| 446 } | |
| 447 | |
| 448 while (constant is DeferredConstantValue) { | |
| 449 assert(context.compiler.compilationFailed); | |
| 450 // TODO(ahe): This isn't correct, and only serves to prevent the | |
| 451 // compiler from crashing. However, the compiler does print a lot of | |
| 452 // errors about not supporting deferred loading, so it should be fine. | |
| 453 constant = constant.referenced; | |
| 454 } | |
| 455 | |
| 456 if (constant.isInt) { | |
| 457 var value = constant.primitiveValue; | |
| 458 if (value > maxInt64 || value < minInt64) { | |
| 459 assert(context.enableBigint); | |
| 460 bool negative = value < 0; | |
| 461 value = negative ? -value : value; | |
| 462 var parts = new List(); | |
| 463 while (value != 0) { | |
| 464 parts.add(value & 0xffffffff); | |
| 465 value >>= 32; | |
| 466 } | |
| 467 | |
| 468 // TODO(ajohnsen): Avoid usage of builders (should be FletchClass). | |
| 469 FletchClassBuilder bigintClassBuilder = | |
| 470 _classBuildersByElement[context.backend.bigintClass]; | |
| 471 FletchClassBuilder uint32DigitsClassBuilder = | |
| 472 _classBuildersByElement[context.backend.uint32DigitsClass]; | |
| 473 | |
| 474 commands.add(new PushNewBigInteger( | |
| 475 negative, | |
| 476 parts, | |
| 477 MapId.classes, | |
| 478 bigintClassBuilder.classId, | |
| 479 uint32DigitsClassBuilder.classId)); | |
| 480 } else { | |
| 481 commands.add(new PushNewInteger(constant.primitiveValue)); | |
| 482 } | |
| 483 } else if (constant.isDouble) { | |
| 484 commands.add(new PushNewDouble(constant.primitiveValue)); | |
| 485 } else if (constant.isTrue) { | |
| 486 commands.add(new PushBoolean(true)); | |
| 487 } else if (constant.isFalse) { | |
| 488 commands.add(new PushBoolean(false)); | |
| 489 } else if (constant.isNull) { | |
| 490 commands.add(const PushNull()); | |
| 491 } else if (constant.isString) { | |
| 492 Iterable<int> list = constant.primitiveValue.slowToString().codeUnits; | |
| 493 if (list.any((codeUnit) => codeUnit >= 256)) { | |
| 494 commands.add(new PushNewTwoByteString(new Uint16List.fromList(list))); | |
| 495 } else { | |
| 496 commands.add(new PushNewOneByteString(new Uint8List.fromList(list))); | |
| 497 } | |
| 498 } else if (constant.isList) { | |
| 499 addList(constant.entries, true); | |
| 500 } else if (constant.isMap) { | |
| 501 MapConstantValue value = constant; | |
| 502 addList(value.keys, false); | |
| 503 addList(value.values, false); | |
| 504 commands.add(new PushConstantMap(value.length * 2)); | |
| 505 } else if (constant.isFunction) { | |
| 506 FunctionConstantValue value = constant; | |
| 507 FunctionElement element = value.element; | |
| 508 FletchFunctionBase function = lookupFunctionByElement(element); | |
| 509 int tearoffId = lookupTearOffById(function.functionId); | |
| 510 FletchFunctionBase tearoff = lookupFunction(tearoffId); | |
| 511 commands | |
| 512 ..add(new PushFromMap(MapId.classes, tearoff.memberOf)) | |
| 513 ..add(const PushNewInstance()); | |
| 514 } else if (constant.isConstructedObject) { | |
| 515 ConstructedConstantValue value = constant; | |
| 516 ClassElement classElement = value.type.element; | |
| 517 // TODO(ajohnsen): Avoid usage of builders (should be FletchClass). | |
| 518 FletchClassBuilder classBuilder = _classBuildersByElement[classElement]; | |
| 519 | |
| 520 void addIfField(MemberElement member) { | |
| 521 if (!member.isField || member.isStatic || member.isPatch) return; | |
| 522 FieldElement fieldElement = member; | |
| 523 ConstantValue fieldValue = value.fields[fieldElement]; | |
| 524 int fieldId = lookupConstantIdByValue(fieldValue); | |
| 525 commands.add(new PushFromMap(MapId.constants, fieldId)); | |
| 526 } | |
| 527 | |
| 528 // Adds all the fields of [currentClass] in order starting from the top | |
| 529 // of the inheritance chain, and for each class adds non-patch fields | |
| 530 // before patch fields. | |
| 531 void addFields(ClassElement currentClass) { | |
| 532 if (currentClass.superclass != null) { | |
| 533 addFields(currentClass.superclass); | |
| 534 } | |
| 535 currentClass.forEachLocalMember(addIfField); | |
| 536 if (currentClass.isPatched) { | |
| 537 currentClass.patch.forEachLocalMember(addIfField); | |
| 538 } | |
| 539 } | |
| 540 | |
| 541 addFields(classElement); | |
| 542 | |
| 543 commands | |
| 544 ..add(new PushFromMap(MapId.classes, classBuilder.classId)) | |
| 545 ..add(const PushNewInstance()); | |
| 546 } else if (constant is FletchClassInstanceConstant) { | |
| 547 commands | |
| 548 ..add(new PushFromMap(MapId.classes, constant.classId)) | |
| 549 ..add(const PushNewInstance()); | |
| 550 } else if (constant.isType) { | |
| 551 // TODO(kasperl): Implement proper support for class literals. At this | |
| 552 // point, we've already issues unimplemented errors for the individual | |
| 553 // accesses to the class literals, so we just let the class literal | |
| 554 // turn into null in the runtime. | |
| 555 commands.add(const PushNull()); | |
| 556 } else { | |
| 557 throw "Unsupported constant: ${constant.toStructuredString()}"; | |
| 558 } | |
| 559 FletchConstant fletchConstant = new FletchConstant(id, MapId.constants); | |
| 560 constantsByValue = constantsByValue.insert(constant, fletchConstant); | |
| 561 constantsById = constantsById.insert(id, fletchConstant); | |
| 562 commands.add(new PopToMap(MapId.constants, id)); | |
| 563 }); | |
| 564 | |
| 565 // Set super class for classes, now they are resolved. | |
| 566 for (FletchClass klass in classes) { | |
| 567 if (!klass.hasSuperclassId) continue; | |
| 568 commands.add(new PushFromMap(MapId.classes, klass.classId)); | |
| 569 commands.add(new PushFromMap(MapId.classes, klass.superclassId)); | |
| 570 commands.add(const ChangeSuperClass()); | |
| 571 changes++; | |
| 572 } | |
| 573 | |
| 574 // Change constants for the functions, now that classes and constants has | |
| 575 // been added. | |
| 576 for (FletchFunction function in functions) { | |
| 577 List<FletchConstant> constants = function.constants; | |
| 578 for (int i = 0; i < constants.length; i++) { | |
| 579 FletchConstant constant = constants[i]; | |
| 580 commands | |
| 581 ..add(new PushFromMap(MapId.methods, function.functionId)) | |
| 582 ..add(new PushFromMap(constant.mapId, constant.id)) | |
| 583 ..add(new ChangeMethodLiteral(i)); | |
| 584 changes++; | |
| 585 } | |
| 586 } | |
| 587 | |
| 588 // Compute all scheme changes. | |
| 589 for (FletchClassBuilder builder in _newClasses.values) { | |
| 590 if (builder.computeSchemaChange(commands)) changes++; | |
| 591 } | |
| 592 | |
| 593 List<FletchFunction> changedFunctions = <FletchFunction>[]; | |
| 594 for (Element element in _replaceUsage.keys) { | |
| 595 // Don't modify already replaced elements. | |
| 596 if (lookupFunctionBuilderByElement(element) != null) continue; | |
| 597 | |
| 598 FletchFunction function = | |
| 599 predecessorSystem.lookupFunctionByElement(element); | |
| 600 // Due to false positive, the element can be uncompiled. | |
| 601 if (function == null) continue; | |
| 602 | |
| 603 bool constantsChanged = false; | |
| 604 List<FletchConstant> constants = function.constants.toList(); | |
| 605 for (int i = 0; i < constants.length; i++) { | |
| 606 FletchConstant constant = constants[i]; | |
| 607 if (constant.mapId != MapId.methods) continue; | |
| 608 for (var usage in _replaceUsage[element]) { | |
| 609 FletchFunction oldFunction = | |
| 610 predecessorSystem.lookupFunctionByElement(usage); | |
| 611 if (oldFunction == null) continue; | |
| 612 if (oldFunction.functionId != constant.id) continue; | |
| 613 FletchFunctionBuilder newFunction = | |
| 614 lookupFunctionBuilderByElement(usage); | |
| 615 | |
| 616 // If the method didn't really change, ignore. | |
| 617 if (newFunction == null) continue; | |
| 618 | |
| 619 constant = new FletchConstant(newFunction.functionId, MapId.methods); | |
| 620 commands | |
| 621 ..add(new PushFromMap(MapId.methods, function.functionId)) | |
| 622 ..add(new PushFromMap(constant.mapId, constant.id)) | |
| 623 ..add(new ChangeMethodLiteral(i)); | |
| 624 constants[i] = constant; | |
| 625 constantsChanged = true; | |
| 626 changes++; | |
| 627 break; | |
| 628 } | |
| 629 } | |
| 630 | |
| 631 if (constantsChanged) { | |
| 632 changedFunctions.add(function.withReplacedConstants(constants)); | |
| 633 } | |
| 634 } | |
| 635 | |
| 636 commands.add(new CommitChanges(changes)); | |
| 637 | |
| 638 PersistentMap<int, FletchClass> classesById = predecessorSystem.classesById; | |
| 639 PersistentMap<ClassElement, FletchClass> classesByElement = | |
| 640 predecessorSystem.classesByElement; | |
| 641 | |
| 642 for (FletchClass klass in classes) { | |
| 643 classesById = classesById.insert(klass.classId, klass); | |
| 644 if (klass.element != null) { | |
| 645 classesByElement = classesByElement.insert(klass.element, klass); | |
| 646 } | |
| 647 } | |
| 648 | |
| 649 PersistentMap<int, FletchFunction> functionsById = | |
| 650 predecessorSystem.functionsById; | |
| 651 PersistentMap<Element, FletchFunction> functionsByElement = | |
| 652 predecessorSystem.functionsByElement; | |
| 653 | |
| 654 for (FletchFunction function in changedFunctions) { | |
| 655 assert(functionsById[function.functionId] != null); | |
| 656 functionsById = functionsById.insert(function.functionId, function); | |
| 657 Element element = function.element; | |
| 658 if (element != null) { | |
| 659 assert(functionsByElement[element] != null); | |
| 660 functionsByElement = functionsByElement.insert(element, function); | |
| 661 } | |
| 662 } | |
| 663 | |
| 664 for (FletchFunction function in _removedFunctions) { | |
| 665 functionsById = functionsById.delete(function.functionId); | |
| 666 Element element = function.element; | |
| 667 if (element != null) { | |
| 668 functionsByElement = functionsByElement.delete(element); | |
| 669 } | |
| 670 } | |
| 671 | |
| 672 for (FletchFunction function in functions) { | |
| 673 functionsById = functionsById.insert(function.functionId, function); | |
| 674 } | |
| 675 | |
| 676 _functionBuildersByElement.forEach((element, builder) { | |
| 677 functionsByElement = functionsByElement.insert( | |
| 678 element, | |
| 679 functionsById[builder.functionId], | |
| 680 (oldValue, newValue) { | |
| 681 throw "Unexpected element in predecessorSystem."; | |
| 682 }); | |
| 683 }); | |
| 684 | |
| 685 PersistentMap<ConstructorElement, FletchFunction> | |
| 686 constructorInitializersByElement = | |
| 687 predecessorSystem.constructorInitializersByElement; | |
| 688 | |
| 689 _newConstructorInitializers.forEach((element, builder) { | |
| 690 constructorInitializersByElement = | |
| 691 constructorInitializersByElement.insert( | |
| 692 element, functionsById[builder.functionId]); | |
| 693 }); | |
| 694 | |
| 695 PersistentMap<int, int> tearoffsById = predecessorSystem.tearoffsById; | |
| 696 _newTearoffsById.forEach((int functionId, int stubId) { | |
| 697 tearoffsById = tearoffsById.insert(functionId, stubId); | |
| 698 }); | |
| 699 | |
| 700 PersistentMap<int, String> symbolByFletchSelectorId = | |
| 701 predecessorSystem.symbolByFletchSelectorId; | |
| 702 _symbolByFletchSelectorId.forEach((int id, String name) { | |
| 703 symbolByFletchSelectorId = symbolByFletchSelectorId.insert(id, name); | |
| 704 }); | |
| 705 | |
| 706 PersistentMap<int, int> gettersByFieldIndex = | |
| 707 predecessorSystem.gettersByFieldIndex; | |
| 708 _newGettersByFieldIndex.forEach((int fieldIndex, int functionId) { | |
| 709 gettersByFieldIndex = gettersByFieldIndex.insert(fieldIndex, functionId); | |
| 710 }); | |
| 711 | |
| 712 PersistentMap<int, int> settersByFieldIndex = | |
| 713 predecessorSystem.settersByFieldIndex; | |
| 714 _newSettersByFieldIndex.forEach((int fieldIndex, int functionId) { | |
| 715 settersByFieldIndex = settersByFieldIndex.insert(fieldIndex, functionId); | |
| 716 }); | |
| 717 | |
| 718 PersistentMap<ParameterStubSignature, FletchFunction> parameterStubs = | |
| 719 predecessorSystem.parameterStubs; | |
| 720 _newParameterStubs.forEach((signature, functionBuilder) { | |
| 721 FletchFunction function = functionsById[functionBuilder.functionId]; | |
| 722 parameterStubs = parameterStubs.insert(signature, function); | |
| 723 }); | |
| 724 | |
| 725 return new FletchSystem( | |
| 726 functionsById, | |
| 727 functionsByElement, | |
| 728 constructorInitializersByElement, | |
| 729 tearoffsById, | |
| 730 classesById, | |
| 731 classesByElement, | |
| 732 constantsById, | |
| 733 constantsByValue, | |
| 734 symbolByFletchSelectorId, | |
| 735 gettersByFieldIndex, | |
| 736 settersByFieldIndex, | |
| 737 parameterStubs); | |
| 738 } | |
| 739 } | |
| OLD | NEW |