1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.createOperationDescriptor = createOperationDescriptor;
|
7 | exports.attemptToMergeEquivalentObjectAssigns = attemptToMergeEquivalentObjectAssigns;
|
8 | exports.Generator = exports.TemporalObjectAssignEntry = exports.TemporalOperationEntry = exports.GeneratorEntry = void 0;
|
9 |
|
10 | var _index = require("../values/index.js");
|
11 |
|
12 | var _errors = require("../errors.js");
|
13 |
|
14 | var _index2 = require("../domains/index.js");
|
15 |
|
16 | var _invariant = _interopRequireDefault(require("../invariant.js"));
|
17 |
|
18 | var _completions = require("../completions.js");
|
19 |
|
20 | var _singletons = require("../singletons.js");
|
21 |
|
22 | var _PreludeGenerator = require("./PreludeGenerator.js");
|
23 |
|
24 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
25 |
|
26 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
|
27 |
|
28 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
29 |
|
30 | function createOperationDescriptor(type, data = {}) {
|
31 | return {
|
32 | data,
|
33 | type
|
34 | };
|
35 | }
|
36 |
|
37 | class GeneratorEntry {
|
38 | constructor(realm) {
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 | this.index = realm.temporalEntryCounter++;
|
46 | }
|
47 |
|
48 | visit(callbacks, containingGenerator) {
|
49 | (0, _invariant.default)(false, "GeneratorEntry is an abstract base class");
|
50 | }
|
51 |
|
52 | serialize(context) {
|
53 | (0, _invariant.default)(false, "GeneratorEntry is an abstract base class");
|
54 | }
|
55 |
|
56 | getDependencies() {
|
57 | (0, _invariant.default)(false, "GeneratorEntry is an abstract base class");
|
58 | }
|
59 |
|
60 | notEqualToAndDoesNotHappenBefore(entry) {
|
61 | return this.index > entry.index;
|
62 | }
|
63 |
|
64 | notEqualToAndDoesNotHappenAfter(entry) {
|
65 | return this.index < entry.index;
|
66 | }
|
67 |
|
68 | }
|
69 |
|
70 | exports.GeneratorEntry = GeneratorEntry;
|
71 |
|
72 | class TemporalOperationEntry extends GeneratorEntry {
|
73 | constructor(realm, args) {
|
74 | super(realm);
|
75 | Object.assign(this, args);
|
76 |
|
77 | if (this.mutatesOnly !== undefined) {
|
78 | (0, _invariant.default)(!this.isPure);
|
79 |
|
80 | for (let arg of this.mutatesOnly) {
|
81 | (0, _invariant.default)(this.args.includes(arg));
|
82 | }
|
83 | }
|
84 |
|
85 | (0, _invariant.default)(this.operationDescriptor !== undefined);
|
86 | }
|
87 |
|
88 | toDisplayJson(depth) {
|
89 | if (depth <= 0) return `TemporalOperation${this.index}`;
|
90 |
|
91 | let obj = _objectSpread({
|
92 | type: "TemporalOperation"
|
93 | }, this);
|
94 |
|
95 | delete obj.operationDescriptor;
|
96 | return _singletons.Utils.verboseToDisplayJson(obj, depth);
|
97 | }
|
98 |
|
99 | visit(callbacks, containingGenerator) {
|
100 | let omit = this.isPure && this.declared && callbacks.canOmit(this.declared);
|
101 |
|
102 | if (!omit && this.declared && this.mutatesOnly !== undefined) {
|
103 | omit = true;
|
104 |
|
105 | for (let arg of this.mutatesOnly) {
|
106 | if (!callbacks.canOmit(arg)) {
|
107 | omit = false;
|
108 | }
|
109 | }
|
110 | }
|
111 |
|
112 | if (omit) {
|
113 | callbacks.recordDelayedEntry(containingGenerator, this);
|
114 | return false;
|
115 | } else {
|
116 | if (this.declared) callbacks.recordDeclaration(this.declared);
|
117 |
|
118 | for (let i = 0, n = this.args.length; i < n; i++) this.args[i] = callbacks.visitEquivalentValue(this.args[i]);
|
119 |
|
120 | if (this.dependencies) for (let dependency of this.dependencies) callbacks.visitGenerator(dependency, containingGenerator);
|
121 | return true;
|
122 | }
|
123 | }
|
124 |
|
125 | serialize(context) {
|
126 | let omit = this.isPure && this.declared && context.canOmit(this.declared);
|
127 |
|
128 | if (!omit && this.declared && this.mutatesOnly !== undefined) {
|
129 | omit = true;
|
130 |
|
131 | for (let arg of this.mutatesOnly) {
|
132 | if (!context.canOmit(arg)) {
|
133 | omit = false;
|
134 | }
|
135 | }
|
136 | }
|
137 |
|
138 | if (!omit) {
|
139 | let nodes = this.args.map((boundArg, i) => context.serializeValue(boundArg));
|
140 | let valuesToProcess = new Set();
|
141 | let declaredId = this.declared !== undefined ? this.declared.intrinsicName : undefined;
|
142 | let node = context.serializeOperationDescriptor(this.operationDescriptor, nodes, context, valuesToProcess, declaredId);
|
143 |
|
144 | if (node.type === "BlockStatement") {
|
145 | let block = node;
|
146 | let statements = block.body;
|
147 | if (statements.length === 0) return;
|
148 |
|
149 | if (statements.length === 1) {
|
150 | node = statements[0];
|
151 | }
|
152 | }
|
153 |
|
154 | let declared = this.declared;
|
155 |
|
156 | if (declared !== undefined && context.options.debugScopes) {
|
157 | context.emit(context.serializeDebugScopeComment(declared));
|
158 | }
|
159 |
|
160 | context.emit(node);
|
161 | context.processValues(valuesToProcess);
|
162 | if (this.declared !== undefined) context.declare(this.declared);
|
163 | }
|
164 | }
|
165 |
|
166 | getDependencies() {
|
167 | return this.dependencies;
|
168 | }
|
169 |
|
170 | }
|
171 |
|
172 | exports.TemporalOperationEntry = TemporalOperationEntry;
|
173 |
|
174 | class TemporalObjectAssignEntry extends TemporalOperationEntry {
|
175 | visit(callbacks, containingGenerator) {
|
176 | let declared = this.declared;
|
177 |
|
178 | if (!(declared instanceof _index.AbstractObjectValue || declared instanceof _index.ObjectValue)) {
|
179 | return false;
|
180 | }
|
181 |
|
182 | let realm = declared.$Realm;
|
183 |
|
184 |
|
185 | let result = attemptToMergeEquivalentObjectAssigns(realm, callbacks, this);
|
186 |
|
187 | if (result instanceof TemporalObjectAssignEntry) {
|
188 | let nextResult = result;
|
189 |
|
190 | while (nextResult instanceof TemporalObjectAssignEntry) {
|
191 | nextResult = attemptToMergeEquivalentObjectAssigns(realm, callbacks, result);
|
192 |
|
193 |
|
194 | if (nextResult instanceof TemporalObjectAssignEntry) {
|
195 | result = nextResult;
|
196 | }
|
197 | }
|
198 |
|
199 |
|
200 |
|
201 | this.args = result.args;
|
202 | } else if (result === "POSSIBLE_OPTIMIZATION") {
|
203 | callbacks.recordDelayedEntry(containingGenerator, this);
|
204 | return false;
|
205 | }
|
206 |
|
207 | return super.visit(callbacks, containingGenerator);
|
208 | }
|
209 |
|
210 | }
|
211 |
|
212 | exports.TemporalObjectAssignEntry = TemporalObjectAssignEntry;
|
213 |
|
214 | class ModifiedPropertyEntry extends GeneratorEntry {
|
215 | constructor(realm, args) {
|
216 | super(realm);
|
217 | Object.assign(this, args);
|
218 | }
|
219 |
|
220 | toDisplayString() {
|
221 | let propertyKey = this.propertyBinding.key;
|
222 | let propertyKeyString = propertyKey instanceof _index.Value ? propertyKey.toDisplayString() : propertyKey;
|
223 | (0, _invariant.default)(propertyKeyString !== undefined);
|
224 | return `[ModifiedProperty ${propertyKeyString}]`;
|
225 | }
|
226 |
|
227 | serialize(context) {
|
228 | let desc = this.propertyBinding.descriptor;
|
229 | (0, _invariant.default)(desc === this.newDescriptor);
|
230 | context.emitPropertyModification(this.propertyBinding);
|
231 | }
|
232 |
|
233 | visit(context, containingGenerator) {
|
234 | (0, _invariant.default)(containingGenerator === this.containingGenerator, "This entry requires effects to be applied and may not be moved");
|
235 | let desc = this.propertyBinding.descriptor;
|
236 | (0, _invariant.default)(desc === this.newDescriptor);
|
237 | context.visitModifiedProperty(this.propertyBinding);
|
238 | return true;
|
239 | }
|
240 |
|
241 | getDependencies() {
|
242 | return undefined;
|
243 | }
|
244 |
|
245 | }
|
246 |
|
247 | class ModifiedBindingEntry extends GeneratorEntry {
|
248 | constructor(realm, args) {
|
249 | super(realm);
|
250 | Object.assign(this, args);
|
251 | }
|
252 |
|
253 | toDisplayString() {
|
254 | return `[ModifiedBinding ${this.modifiedBinding.name}]`;
|
255 | }
|
256 |
|
257 | serialize(context) {
|
258 | context.emitBindingModification(this.modifiedBinding);
|
259 | }
|
260 |
|
261 | visit(context, containingGenerator) {
|
262 | (0, _invariant.default)(containingGenerator === this.containingGenerator, "This entry requires effects to be applied and may not be moved");
|
263 | context.visitModifiedBinding(this.modifiedBinding);
|
264 | return true;
|
265 | }
|
266 |
|
267 | getDependencies() {
|
268 | return undefined;
|
269 | }
|
270 |
|
271 | }
|
272 |
|
273 | class ReturnValueEntry extends GeneratorEntry {
|
274 | constructor(realm, generator, returnValue) {
|
275 | super(realm);
|
276 | this.returnValue = returnValue.promoteEmptyToUndefined();
|
277 | this.containingGenerator = generator;
|
278 | }
|
279 |
|
280 | toDisplayString() {
|
281 | return `[Return ${this.returnValue.toDisplayString()}]`;
|
282 | }
|
283 |
|
284 | visit(context, containingGenerator) {
|
285 | (0, _invariant.default)(containingGenerator === this.containingGenerator, "This entry requires effects to be applied and may not be moved");
|
286 | this.returnValue = context.visitEquivalentValue(this.returnValue);
|
287 | return true;
|
288 | }
|
289 |
|
290 | serialize(context) {
|
291 | context.emit(context.serializeReturnValue(this.returnValue));
|
292 | }
|
293 |
|
294 | getDependencies() {
|
295 | return undefined;
|
296 | }
|
297 |
|
298 | }
|
299 |
|
300 | class BindingAssignmentEntry extends GeneratorEntry {
|
301 | constructor(realm, binding, value) {
|
302 | super(realm);
|
303 | this.binding = binding;
|
304 | this.value = value;
|
305 | }
|
306 |
|
307 | toDisplayString() {
|
308 | return `[BindingAssignment ${this.binding.name} = ${this.value.toDisplayString()}]`;
|
309 | }
|
310 |
|
311 | serialize(context) {
|
312 | context.emit(context.serializeBindingAssignment(this.binding, this.value));
|
313 | }
|
314 |
|
315 | visit(context, containingGenerator) {
|
316 | this.value = context.visitBindingAssignment(this.binding, this.value);
|
317 | return true;
|
318 | }
|
319 |
|
320 | getDependencies() {
|
321 | return undefined;
|
322 | }
|
323 |
|
324 | }
|
325 |
|
326 | class Generator {
|
327 | constructor(realm, name, pathConditions, effects) {
|
328 | (0, _invariant.default)(realm.useAbstractInterpretation);
|
329 | let realmPreludeGenerator = realm.preludeGenerator;
|
330 | (0, _invariant.default)(realmPreludeGenerator);
|
331 | this.preludeGenerator = realmPreludeGenerator;
|
332 | this.realm = realm;
|
333 | this._entries = [];
|
334 | this.id = realm.nextGeneratorId++;
|
335 | this._name = name;
|
336 | this.effectsToApply = effects;
|
337 | this.pathConditions = pathConditions;
|
338 | }
|
339 |
|
340 | toDisplayString() {
|
341 | return _singletons.Utils.jsonToDisplayString(this, 2);
|
342 | }
|
343 |
|
344 | toDisplayJson(depth) {
|
345 | if (depth <= 0) return `Generator${this.id}-${this._name}`;
|
346 | return _singletons.Utils.verboseToDisplayJson(this, depth);
|
347 | }
|
348 |
|
349 | static _generatorOfEffects(realm, name, environmentRecordIdAfterGlobalCode, effects) {
|
350 | let {
|
351 | result,
|
352 | generator,
|
353 | modifiedBindings,
|
354 | modifiedProperties,
|
355 | createdObjects
|
356 | } = effects;
|
357 | let output = new Generator(realm, name, generator.pathConditions, effects);
|
358 | output.appendGenerator(generator, generator._name);
|
359 |
|
360 | for (let propertyBinding of modifiedProperties.keys()) {
|
361 | let object = propertyBinding.object;
|
362 | if (createdObjects.has(object)) continue;
|
363 |
|
364 | if (_index.ObjectValue.refuseSerializationOnPropertyBinding(propertyBinding)) continue;
|
365 |
|
366 |
|
367 | if (object.isIntrinsic()) continue;
|
368 | output.emitPropertyModification(propertyBinding);
|
369 | }
|
370 |
|
371 | for (let modifiedBinding of modifiedBindings.keys()) {
|
372 |
|
373 |
|
374 |
|
375 | if (modifiedBinding.environment.id >= environmentRecordIdAfterGlobalCode) continue;
|
376 | output.emitBindingModification(modifiedBinding);
|
377 | }
|
378 |
|
379 | if (result instanceof _index.UndefinedValue) return output;
|
380 |
|
381 | if (result instanceof _completions.SimpleNormalCompletion) {
|
382 | output.emitReturnValue(result.value);
|
383 | } else if (result instanceof _completions.ThrowCompletion) {
|
384 | output.emitThrow(result.value);
|
385 | } else if (result instanceof _completions.JoinedNormalAndAbruptCompletions) {
|
386 | let selector = c => c instanceof _completions.ThrowCompletion && c.value !== realm.intrinsics.__bottomValue && !(c.value instanceof _index.EmptyValue);
|
387 |
|
388 | output.emitConditionalThrow(_singletons.Join.joinValuesOfSelectedCompletions(selector, result));
|
389 | output.emitReturnValue(result.value);
|
390 | } else {
|
391 | (0, _invariant.default)(false);
|
392 | }
|
393 |
|
394 | return output;
|
395 | }
|
396 |
|
397 |
|
398 |
|
399 | static fromEffects(effects, realm, name, environmentRecordIdAfterGlobalCode = 0) {
|
400 | return realm.withEffectsAppliedInGlobalEnv(this._generatorOfEffects.bind(this, realm, name, environmentRecordIdAfterGlobalCode), effects);
|
401 | }
|
402 |
|
403 | emitPropertyModification(propertyBinding) {
|
404 | (0, _invariant.default)(this.effectsToApply !== undefined);
|
405 | let desc = propertyBinding.descriptor;
|
406 |
|
407 | if (desc !== undefined) {
|
408 | let value = desc.value;
|
409 |
|
410 | if (value instanceof _index.AbstractValue) {
|
411 | if (value.kind === "conditional") {
|
412 | let [c, x, y] = value.args;
|
413 |
|
414 | if (c instanceof _index.AbstractValue && c.kind === "template for property name condition") {
|
415 | let ydesc = Object.assign({}, desc, {
|
416 | value: y
|
417 | });
|
418 | let yprop = Object.assign({}, propertyBinding, {
|
419 | descriptor: ydesc
|
420 | });
|
421 | this.emitPropertyModification(yprop);
|
422 | let xdesc = Object.assign({}, desc, {
|
423 | value: x
|
424 | });
|
425 | let key = c.args[0];
|
426 | (0, _invariant.default)(key instanceof _index.AbstractValue);
|
427 | let xprop = Object.assign({}, propertyBinding, {
|
428 | key,
|
429 | descriptor: xdesc
|
430 | });
|
431 | this.emitPropertyModification(xprop);
|
432 | return;
|
433 | }
|
434 | } else if (value.kind === "template for prototype member expression") {
|
435 | return;
|
436 | }
|
437 | }
|
438 | }
|
439 |
|
440 | this._entries.push(new ModifiedPropertyEntry(this.realm, {
|
441 | propertyBinding,
|
442 | newDescriptor: desc,
|
443 | containingGenerator: this
|
444 | }));
|
445 | }
|
446 |
|
447 | emitBindingModification(modifiedBinding) {
|
448 | (0, _invariant.default)(this.effectsToApply !== undefined);
|
449 |
|
450 | this._entries.push(new ModifiedBindingEntry(this.realm, {
|
451 | modifiedBinding,
|
452 | containingGenerator: this
|
453 | }));
|
454 | }
|
455 |
|
456 | emitReturnValue(result) {
|
457 | this._entries.push(new ReturnValueEntry(this.realm, this, result));
|
458 | }
|
459 |
|
460 | getName() {
|
461 | return `${this._name}(#${this.id})`;
|
462 | }
|
463 |
|
464 | empty() {
|
465 | return this._entries.length === 0;
|
466 | }
|
467 |
|
468 | emitGlobalDeclaration(key, value) {
|
469 | this.preludeGenerator.declaredGlobals.add(key);
|
470 | if (!(value instanceof _index.UndefinedValue)) this.emitGlobalAssignment(key, value);
|
471 | }
|
472 |
|
473 | emitGlobalAssignment(key, value) {
|
474 | this._addEntry({
|
475 | args: [value, new _index.StringValue(this.realm, key)],
|
476 | operationDescriptor: createOperationDescriptor("GLOBAL_ASSIGNMENT")
|
477 | });
|
478 | }
|
479 |
|
480 | emitConcreteModel(key, value) {
|
481 | this._addEntry({
|
482 | args: [(0, _singletons.concretize)(this.realm, value), new _index.StringValue(this.realm, key)],
|
483 | operationDescriptor: createOperationDescriptor("CONCRETE_MODEL")
|
484 | });
|
485 | }
|
486 |
|
487 | emitGlobalDelete(key) {
|
488 | this._addEntry({
|
489 | args: [new _index.StringValue(this.realm, key)],
|
490 | operationDescriptor: createOperationDescriptor("GLOBAL_DELETE")
|
491 | });
|
492 | }
|
493 |
|
494 | emitBindingAssignment(binding, value) {
|
495 | this._entries.push(new BindingAssignmentEntry(this.realm, binding, value));
|
496 | }
|
497 |
|
498 | emitPropertyAssignment(object, key, value) {
|
499 | if (object instanceof _index.ObjectValue && object.refuseSerialization) {
|
500 | return;
|
501 | }
|
502 |
|
503 | if (typeof key === "string") {
|
504 | key = new _index.StringValue(this.realm, key);
|
505 | }
|
506 |
|
507 | this._addEntry({
|
508 | args: [object, value, key],
|
509 | operationDescriptor: createOperationDescriptor("EMIT_PROPERTY_ASSIGNMENT", {
|
510 | value
|
511 | })
|
512 | });
|
513 | }
|
514 |
|
515 | emitDefineProperty(object, key, desc, isDescChanged = true) {
|
516 | if (object.refuseSerialization) return;
|
517 |
|
518 | if (desc.enumerable && desc.configurable && desc.writable && desc.value && !isDescChanged) {
|
519 | let descValue = desc.value;
|
520 | (0, _invariant.default)(descValue instanceof _index.Value);
|
521 | this.emitPropertyAssignment(object, key, descValue);
|
522 | } else {
|
523 | desc = Object.assign({}, desc);
|
524 | let descValue = desc.value || object.$Realm.intrinsics.undefined;
|
525 | (0, _invariant.default)(descValue instanceof _index.Value);
|
526 |
|
527 | this._addEntry({
|
528 | args: [new _index.StringValue(this.realm, key), object, descValue, desc.get || object.$Realm.intrinsics.undefined, desc.set || object.$Realm.intrinsics.undefined],
|
529 | operationDescriptor: createOperationDescriptor("DEFINE_PROPERTY", {
|
530 | object,
|
531 | desc
|
532 | })
|
533 | });
|
534 | }
|
535 | }
|
536 |
|
537 | emitPropertyDelete(object, key) {
|
538 | if (object.refuseSerialization) return;
|
539 |
|
540 | this._addEntry({
|
541 | args: [object, new _index.StringValue(this.realm, key)],
|
542 | operationDescriptor: createOperationDescriptor("PROPERTY_DELETE")
|
543 | });
|
544 | }
|
545 |
|
546 | emitCall(callFunctionRef, args) {
|
547 | this._addEntry({
|
548 | args,
|
549 | operationDescriptor: createOperationDescriptor("EMIT_CALL", {
|
550 | callFunctionRef
|
551 | })
|
552 | });
|
553 | }
|
554 |
|
555 | emitConsoleLog(method, args) {
|
556 | this._addEntry({
|
557 | args: [new _index.StringValue(this.realm, method), ...args.map(v => typeof v === "string" ? new _index.StringValue(this.realm, v) : v)],
|
558 | operationDescriptor: createOperationDescriptor("CONSOLE_LOG")
|
559 | });
|
560 | }
|
561 |
|
562 |
|
563 | emitDoWhileStatement(test, body) {
|
564 | this._addEntry({
|
565 | args: [],
|
566 | operationDescriptor: createOperationDescriptor("DO_WHILE", {
|
567 | generator: body,
|
568 | value: test
|
569 | }),
|
570 | dependencies: [body]
|
571 | });
|
572 | }
|
573 |
|
574 | emitConditionalThrow(value) {
|
575 | if (value instanceof _index.EmptyValue) return;
|
576 |
|
577 | this._issueThrowCompilerDiagnostic(value);
|
578 |
|
579 | this._addEntry({
|
580 | args: [value],
|
581 | operationDescriptor: createOperationDescriptor("CONDITIONAL_THROW", {
|
582 | value
|
583 | })
|
584 | });
|
585 | }
|
586 |
|
587 | _issueThrowCompilerDiagnostic(value) {
|
588 | let message = "Program may terminate with exception";
|
589 |
|
590 | if (value instanceof _index.ObjectValue) {
|
591 | let object = value;
|
592 | let objectMessage = this.realm.evaluateWithUndo(() => object._SafeGetDataPropertyValue("message"));
|
593 | if (objectMessage instanceof _index.StringValue) message += `: ${objectMessage.value}`;
|
594 | const objectStack = this.realm.evaluateWithUndo(() => object._SafeGetDataPropertyValue("stack"));
|
595 | if (objectStack instanceof _index.StringValue) message += `
|
596 | ${objectStack.value}`;
|
597 | }
|
598 |
|
599 | const diagnostic = new _errors.CompilerDiagnostic(message, value.expressionLocation, "PP0023", "Warning");
|
600 | this.realm.handleError(diagnostic);
|
601 | }
|
602 |
|
603 | emitThrow(value) {
|
604 | this._issueThrowCompilerDiagnostic(value);
|
605 |
|
606 | this.emitStatement([value], createOperationDescriptor("THROW"));
|
607 | }
|
608 |
|
609 |
|
610 |
|
611 |
|
612 |
|
613 | emitFullInvariant(object, key, value) {
|
614 | if (object.refuseSerialization) return;
|
615 |
|
616 | if (value instanceof _index.AbstractValue) {
|
617 | let isTop = false;
|
618 | let concreteComparisons = [];
|
619 | let typeComparisons = new Set();
|
620 |
|
621 | function populateComparisonsLists(absValue) {
|
622 | if (absValue.kind === "abstractConcreteUnion") {
|
623 |
|
624 | for (let nestedValue of absValue.args) if (nestedValue instanceof _index.ConcreteValue) {
|
625 | concreteComparisons.push(nestedValue);
|
626 | } else {
|
627 | (0, _invariant.default)(nestedValue instanceof _index.AbstractValue);
|
628 | populateComparisonsLists(nestedValue);
|
629 | }
|
630 | } else if (absValue.getType() === _index.Value) {
|
631 | isTop = true;
|
632 | } else {
|
633 | typeComparisons.add(absValue.getType());
|
634 | }
|
635 | }
|
636 |
|
637 | populateComparisonsLists(value);
|
638 |
|
639 |
|
640 | if (isTop) {
|
641 | return;
|
642 | } else {
|
643 | this._emitInvariant([new _index.StringValue(this.realm, key), value, value], createOperationDescriptor("FULL_INVARIANT_ABSTRACT", {
|
644 | concreteComparisons,
|
645 | typeComparisons
|
646 | }), createOperationDescriptor("INVARIANT_APPEND"));
|
647 | }
|
648 | } else if (value instanceof _index.FunctionValue) {
|
649 |
|
650 |
|
651 |
|
652 | this._emitInvariant([new _index.StringValue(this.realm, key), object, value, object], createOperationDescriptor("FULL_INVARIANT_FUNCTION"), createOperationDescriptor("INVARIANT_APPEND"));
|
653 | } else {
|
654 | this._emitInvariant([new _index.StringValue(this.realm, key), object, value, object], createOperationDescriptor("FULL_INVARIANT"), createOperationDescriptor("INVARIANT_APPEND"));
|
655 | }
|
656 | }
|
657 |
|
658 | emitPropertyInvariant(object, key, state) {
|
659 | if (object.refuseSerialization) return;
|
660 |
|
661 | this._emitInvariant([new _index.StringValue(this.realm, key), object, object], createOperationDescriptor("PROPERTY_INVARIANT", {
|
662 | state
|
663 | }), createOperationDescriptor("INVARIANT_APPEND"));
|
664 | }
|
665 |
|
666 | _emitInvariant(args, violationConditionOperationDescriptor, appendLastToInvariantOperationDescriptor) {
|
667 | (0, _invariant.default)(this.realm.invariantLevel > 0);
|
668 | let invariantOperationDescriptor = createOperationDescriptor("INVARIANT", {
|
669 | appendLastToInvariantOperationDescriptor,
|
670 | violationConditionOperationDescriptor
|
671 | });
|
672 |
|
673 | this._addEntry({
|
674 | args,
|
675 | operationDescriptor: invariantOperationDescriptor
|
676 | });
|
677 | }
|
678 |
|
679 | emitCallAndCaptureResult(types, values, callFunctionRef, args, kind) {
|
680 | return this.deriveAbstract(types, values, args, createOperationDescriptor("EMIT_CALL_AND_CAPTURE_RESULT", {
|
681 | callFunctionRef
|
682 | }), {
|
683 | kind
|
684 | });
|
685 | }
|
686 |
|
687 | emitStatement(args, operationDescriptor) {
|
688 | (0, _invariant.default)(typeof operationDescriptor !== "function");
|
689 |
|
690 | this._addEntry({
|
691 | args,
|
692 | operationDescriptor
|
693 | });
|
694 | }
|
695 |
|
696 | emitVoidExpression(types, values, args, operationDescriptor) {
|
697 | this._addEntry({
|
698 | args,
|
699 | operationDescriptor
|
700 | });
|
701 |
|
702 | return this.realm.intrinsics.undefined;
|
703 | }
|
704 |
|
705 | emitForInStatement(o, lh, sourceObject, targetObject, boundName) {
|
706 | this._addEntry({
|
707 |
|
708 | args: [o, targetObject, sourceObject, targetObject, sourceObject],
|
709 | operationDescriptor: createOperationDescriptor("FOR_IN", {
|
710 | boundName,
|
711 | lh
|
712 | })
|
713 | });
|
714 | }
|
715 |
|
716 | deriveConcreteObject(buildValue, args, operationDescriptor, optionalArgs) {
|
717 | let id = this.preludeGenerator.nameGenerator.generate("derived");
|
718 | let value = buildValue(id);
|
719 | value.intrinsicNameGenerated = true;
|
720 | value._isScopedTemplate = true;
|
721 |
|
722 | (0, _invariant.default)(value.intrinsicName === id);
|
723 |
|
724 | this._addDerivedEntry({
|
725 | isPure: optionalArgs ? optionalArgs.isPure : undefined,
|
726 | declared: value,
|
727 | args,
|
728 | operationDescriptor
|
729 | });
|
730 |
|
731 | return value;
|
732 | }
|
733 |
|
734 | deriveAbstract(types, values, args, operationDescriptor, optionalArgs) {
|
735 | let id = this.preludeGenerator.nameGenerator.generate("derived");
|
736 | let options = {};
|
737 | if (optionalArgs && optionalArgs.kind !== undefined) options.kind = optionalArgs.kind;
|
738 | if (optionalArgs && optionalArgs.shape !== undefined) options.shape = optionalArgs.shape;
|
739 | let Constructor = _index.Value.isTypeCompatibleWith(types.getType(), _index.ObjectValue) ? _index.AbstractObjectValue : _index.AbstractValue;
|
740 | let res = new Constructor(this.realm, types, values, 1735003607742176 + this.realm.derivedIds.size, [], createOperationDescriptor("IDENTIFIER", {
|
741 | id
|
742 | }), options);
|
743 | res.intrinsicName = id;
|
744 |
|
745 | this._addDerivedEntry({
|
746 | isPure: optionalArgs ? optionalArgs.isPure : undefined,
|
747 | declared: res,
|
748 | args,
|
749 | operationDescriptor,
|
750 | mutatesOnly: optionalArgs ? optionalArgs.mutatesOnly : undefined
|
751 | });
|
752 |
|
753 | let type = types.getType();
|
754 | if (optionalArgs && optionalArgs.skipInvariant) return res;
|
755 | let typeofString;
|
756 | if (type instanceof _index.FunctionValue) typeofString = "function";else if (type === _index.UndefinedValue) (0, _invariant.default)(false);else if (type === _index.NullValue) (0, _invariant.default)(false);else if (type === _index.StringValue) typeofString = "string";else if (type === _index.BooleanValue) typeofString = "boolean";else if (type === _index.NumberValue) typeofString = "number";else if (type === _index.IntegralValue) typeofString = "number";else if (type === _index.SymbolValue) typeofString = "symbol";else if (type === _index.ObjectValue) typeofString = "object";
|
757 |
|
758 | if (typeofString !== undefined && this.realm.invariantLevel >= 1) {
|
759 |
|
760 |
|
761 | this._emitInvariant([new _index.StringValue(this.realm, typeofString), res, res], createOperationDescriptor("DERIVED_ABSTRACT_INVARIANT"), createOperationDescriptor("SINGLE_ARG"));
|
762 | }
|
763 |
|
764 | return res;
|
765 | }
|
766 |
|
767 | visit(callbacks) {
|
768 | let visitFn = () => {
|
769 | for (let entry of this._entries) entry.visit(callbacks, this);
|
770 |
|
771 | return null;
|
772 | };
|
773 |
|
774 | if (this.effectsToApply) {
|
775 | this.realm.withEffectsAppliedInGlobalEnv(visitFn, this.effectsToApply);
|
776 | } else {
|
777 | visitFn();
|
778 | }
|
779 | }
|
780 |
|
781 | serialize(context) {
|
782 | let serializeFn = () => {
|
783 | context.initGenerator(this);
|
784 |
|
785 | for (let entry of this._entries) entry.serialize(context);
|
786 |
|
787 | context.finalizeGenerator(this);
|
788 | return null;
|
789 | };
|
790 |
|
791 | if (this.effectsToApply) {
|
792 | this.realm.withEffectsAppliedInGlobalEnv(serializeFn, this.effectsToApply);
|
793 | } else {
|
794 | serializeFn();
|
795 | }
|
796 | }
|
797 |
|
798 | getDependencies() {
|
799 | let res = [];
|
800 |
|
801 | for (let entry of this._entries) {
|
802 | let dependencies = entry.getDependencies();
|
803 | if (dependencies !== undefined) res.push(...dependencies);
|
804 | }
|
805 |
|
806 | return res;
|
807 | }
|
808 |
|
809 | _addEntry(entryArgs) {
|
810 | let entry;
|
811 | let operationDescriptor = entryArgs.operationDescriptor;
|
812 |
|
813 | if (operationDescriptor && operationDescriptor.type === "OBJECT_ASSIGN") {
|
814 | entry = new TemporalObjectAssignEntry(this.realm, entryArgs);
|
815 | } else {
|
816 | entry = new TemporalOperationEntry(this.realm, entryArgs);
|
817 | }
|
818 |
|
819 | this.realm.saveTemporalGeneratorEntryArgs(entry);
|
820 |
|
821 | this._entries.push(entry);
|
822 |
|
823 | return entry;
|
824 | }
|
825 |
|
826 | _addDerivedEntry(entryArgs) {
|
827 | let declared = entryArgs.declared;
|
828 | (0, _invariant.default)(declared !== undefined);
|
829 | let id = declared.intrinsicName;
|
830 | (0, _invariant.default)(id !== undefined);
|
831 |
|
832 | let entry = this._addEntry(entryArgs);
|
833 |
|
834 | this.realm.derivedIds.set(id, entry);
|
835 | }
|
836 |
|
837 | appendGenerator(other, leadingComment) {
|
838 | (0, _invariant.default)(other !== this);
|
839 | (0, _invariant.default)(other.realm === this.realm);
|
840 | (0, _invariant.default)(other.preludeGenerator === this.preludeGenerator);
|
841 | (0, _invariant.default)(other.effectsToApply === undefined);
|
842 | if (other.empty()) return;
|
843 |
|
844 | this._entries.push(...other._entries);
|
845 | }
|
846 |
|
847 | joinGenerators(joinCondition, generator1, generator2) {
|
848 | (0, _invariant.default)(generator1 !== this && generator2 !== this && generator1 !== generator2);
|
849 | if (generator1.empty() && generator2.empty()) return;
|
850 | let generators = [generator1, generator2];
|
851 |
|
852 | this._addEntry({
|
853 | args: [joinCondition],
|
854 | operationDescriptor: createOperationDescriptor("JOIN_GENERATORS", {
|
855 | generators
|
856 | }),
|
857 | dependencies: generators
|
858 | });
|
859 | }
|
860 |
|
861 | }
|
862 |
|
863 | exports.Generator = Generator;
|
864 |
|
865 |
|
866 |
|
867 |
|
868 |
|
869 |
|
870 |
|
871 |
|
872 |
|
873 |
|
874 | function attemptToMergeEquivalentObjectAssigns(realm, callbacks, temporalOperationEntry) {
|
875 | let args = temporalOperationEntry.args;
|
876 |
|
877 | if (args.length < 2) {
|
878 | return "NO_OPTIMIZATION";
|
879 | }
|
880 |
|
881 | let to = args[0];
|
882 |
|
883 |
|
884 | loopThroughArgs: for (let i = 1; i < args.length; i++) {
|
885 | let possibleOtherObjectAssignTo = args[i];
|
886 |
|
887 |
|
888 |
|
889 |
|
890 | if (!callbacks.canOmit(possibleOtherObjectAssignTo)) {
|
891 | continue;
|
892 | }
|
893 |
|
894 |
|
895 |
|
896 | if (possibleOtherObjectAssignTo instanceof _index.AbstractObjectValue) {
|
897 | let otherTemporalOperationEntry = realm.getTemporalOperationEntryFromDerivedValue(possibleOtherObjectAssignTo);
|
898 |
|
899 | if (!(otherTemporalOperationEntry instanceof TemporalObjectAssignEntry)) {
|
900 | continue;
|
901 | }
|
902 |
|
903 | let otherArgs = otherTemporalOperationEntry.args;
|
904 |
|
905 | if (otherArgs.length < 1) {
|
906 | continue;
|
907 | }
|
908 |
|
909 | let otherArgsToUse = [];
|
910 |
|
911 | for (let x = 1; x < otherArgs.length; x++) {
|
912 | let arg = otherArgs[x];
|
913 |
|
914 | if (arg instanceof _index.ObjectValue && arg.mightBeLeakedObject()) {
|
915 | continue loopThroughArgs;
|
916 | }
|
917 |
|
918 | if (arg instanceof _index.ObjectValue || arg instanceof _index.AbstractValue) {
|
919 | let temporalGeneratorEntries = realm.getTemporalGeneratorEntriesReferencingArg(arg);
|
920 |
|
921 |
|
922 |
|
923 | if (temporalGeneratorEntries !== undefined) {
|
924 | for (let temporalGeneratorEntry of temporalGeneratorEntries) {
|
925 |
|
926 |
|
927 |
|
928 | if (temporalGeneratorEntry instanceof TemporalObjectAssignEntry) {
|
929 | continue;
|
930 | }
|
931 |
|
932 |
|
933 |
|
934 |
|
935 |
|
936 |
|
937 | if (temporalGeneratorEntry.notEqualToAndDoesNotHappenBefore(otherTemporalOperationEntry) && temporalGeneratorEntry.notEqualToAndDoesNotHappenAfter(temporalOperationEntry)) {
|
938 | continue loopThroughArgs;
|
939 | }
|
940 | }
|
941 | }
|
942 | }
|
943 |
|
944 | otherArgsToUse.push(arg);
|
945 | }
|
946 |
|
947 |
|
948 |
|
949 | if (!callbacks.canOmit(to)) {
|
950 |
|
951 |
|
952 | let prefixArgs = args.slice(1, i - 1);
|
953 |
|
954 | let suffixArgs = args.slice(i + 1);
|
955 | let newArgs = [to, ...prefixArgs, ...otherArgsToUse, ...suffixArgs];
|
956 |
|
957 |
|
958 |
|
959 |
|
960 |
|
961 |
|
962 | let newTemporalObjectAssignEntryArgs = Object.assign({}, temporalOperationEntry, {
|
963 | args: newArgs
|
964 | });
|
965 | return new TemporalObjectAssignEntry(realm, newTemporalObjectAssignEntryArgs);
|
966 | }
|
967 |
|
968 |
|
969 |
|
970 |
|
971 |
|
972 | return "POSSIBLE_OPTIMIZATION";
|
973 | }
|
974 | }
|
975 |
|
976 | return "NO_OPTIMIZATION";
|
977 | }
|
978 |
|
\ | No newline at end of file |