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