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 |