UNPKG

8.12 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.HeapInspector = void 0;
7
8var _realm = require("../realm.js");
9
10var _index = require("../methods/index.js");
11
12var _index2 = require("../values/index.js");
13
14var _singletons = require("../singletons.js");
15
16var _invariant = _interopRequireDefault(require("../invariant.js"));
17
18var _logger = require("./logger.js");
19
20function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
22function _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; }
23
24class HeapInspector {
25 constructor(realm, logger) {
26 this.realm = realm;
27 this.logger = logger;
28 this.ignoredProperties = new Map();
29 this._targetIntegrityCommands = new Map();
30 }
31
32 getTargetIntegrityCommand(val) {
33 let command = this._targetIntegrityCommands.get(val);
34
35 if (command === undefined) {
36 command = "";
37
38 if (val instanceof _index2.ProxyValue) {// proxies don't participate in regular object freezing/sealing,
39 // only their underlying proxied objects do
40 } else {
41 let extensible = val.$Extensible;
42
43 if (!(extensible instanceof _index2.BooleanValue)) {
44 this.logger.logError(val, "Object that might or might not be sealed or frozen are not supported in residual heap.");
45 } else if (!extensible.value) {
46 let anyWritable = false,
47 anyConfigurable = false;
48
49 for (let propertyBinding of val.properties.values()) {
50 let desc = propertyBinding.descriptor;
51 if (desc === undefined) continue; //deleted
52
53 if (desc.configurable) anyConfigurable = true;else if (desc.value !== undefined && desc.writable) anyWritable = true;
54 }
55
56 command = anyConfigurable ? "preventExtensions" : anyWritable ? "seal" : "freeze";
57 }
58 }
59
60 this._targetIntegrityCommands.set(val, command);
61 }
62
63 return command;
64 }
65
66 getTargetIntegrityDescriptor(val) {
67 return HeapInspector._integrityDescriptors[this.getTargetIntegrityCommand(val)];
68 }
69
70 static isLeaf(val) {
71 if (val instanceof _index2.SymbolValue) {
72 return false;
73 }
74
75 if (val instanceof _index2.AbstractValue) {
76 if (val.hasIdentifier()) {
77 return true;
78 }
79
80 if (val.$Realm.instantRender.enabled && val.intrinsicName !== undefined && val.intrinsicName.startsWith("__native")) {
81 // Never factor out multiple occurrences of InstantRender's __native... abstract functions.
82 return true;
83 }
84 }
85
86 if (val.isIntrinsic()) {
87 return false;
88 }
89
90 return val instanceof _index2.PrimitiveValue;
91 } // Object properties which have the default value can be ignored by the serializer.
92
93
94 canIgnoreProperty(val, key) {
95 let set = this.ignoredProperties.get(val);
96
97 if (!set) {
98 this.ignoredProperties.set(val, set = this._getIgnoredProperties(val));
99 }
100
101 return set.has(key);
102 }
103
104 _getIgnoredProperties(val) {
105 let set = new Set();
106
107 for (let [key, propertyBinding] of val.properties) {
108 (0, _invariant.default)(propertyBinding);
109 let desc = propertyBinding.descriptor;
110 if (desc === undefined) continue; //deleted
111
112 if (this._canIgnoreProperty(val, key, desc)) set.add(key);
113 }
114
115 return set;
116 }
117
118 _canIgnoreProperty(val, key, desc) {
119 let targetDescriptor = this.getTargetIntegrityDescriptor(val);
120
121 if ((0, _index.IsArray)(this.realm, val)) {
122 if (key === "length" && desc.writable === targetDescriptor.writable && !desc.enumerable && !desc.configurable) {
123 // length property has the correct descriptor values
124 return true;
125 }
126 } else if (val instanceof _index2.FunctionValue) {
127 if (key === "length") {
128 if (desc.value === undefined) {
129 this.logger.logError(val, "Functions with length accessor properties are not supported in residual heap."); // Rationale: .bind() would call the accessor, which might throw, mutate state, or do whatever...
130 } // length property will be inferred already by the amount of parameters
131
132
133 return !desc.writable && !desc.enumerable && desc.configurable === targetDescriptor.configurable && val.hasDefaultLength();
134 }
135
136 if (key === "name") {
137 // TODO #474: Make sure that we retain original function names. Or set name property.
138 // Or ensure that nothing references the name property.
139 // NOTE: with some old runtimes notably JSC, function names are not configurable
140 // For now don't ignore the property if it is different from the function name.
141 // I.e. if it was set explicitly in the code, retain it.
142 if (desc.value !== undefined && !this.realm.isCompatibleWith(this.realm.MOBILE_JSC_VERSION) && !this.realm.isCompatibleWith("mobile") && (desc.value instanceof _index2.AbstractValue || desc.value instanceof _index2.ConcreteValue && val.__originalName && val.__originalName !== "" && _singletons.To.ToString(this.realm, desc.value) !== val.__originalName)) return false;
143 return true;
144 } // Properties `caller` and `arguments` are added to normal functions in non-strict mode to prevent TypeErrors.
145 // Because they are autogenerated, they should be ignored.
146
147
148 if (key === "arguments" || key === "caller") {
149 (0, _invariant.default)(val instanceof _index2.ECMAScriptSourceFunctionValue);
150 if (!val.$Strict && desc.writable === (!val.$Strict && targetDescriptor.writable) && !desc.enumerable && desc.configurable === targetDescriptor.configurable && desc.value instanceof _index2.UndefinedValue && val.$FunctionKind === "normal") return true;
151 } // ignore the `prototype` property when it's the right one
152
153
154 if (key === "prototype") {
155 if (!desc.configurable && !desc.enumerable && desc.writable === targetDescriptor.writable && desc.value instanceof _index2.ObjectValue && desc.value.originalConstructor === val) {
156 return true;
157 }
158 }
159 } else {
160 let kind = val.getKind();
161
162 switch (kind) {
163 case "RegExp":
164 if (key === "lastIndex" && desc.writable === targetDescriptor.writable && !desc.enumerable && !desc.configurable) {
165 // length property has the correct descriptor values
166 let v = desc.value;
167 return v instanceof _index2.NumberValue && v.value === 0;
168 }
169
170 break;
171
172 default:
173 break;
174 }
175 }
176
177 if (key === "constructor") {
178 if (desc.configurable === targetDescriptor.configurable && !desc.enumerable && desc.writable === targetDescriptor.writable && desc.value === val.originalConstructor) return true;
179 }
180
181 return false;
182 }
183
184 static getPropertyValue(val, name) {
185 let prototypeBinding = val.properties.get(name);
186 if (prototypeBinding === undefined) return undefined;
187 let prototypeDesc = prototypeBinding.descriptor;
188 if (prototypeDesc === undefined) return undefined;
189 (0, _invariant.default)(prototypeDesc.value === undefined || prototypeDesc.value instanceof _index2.Value);
190 return prototypeDesc.value;
191 }
192
193 isDefaultPrototype(prototype) {
194 if (prototype.symbols.size !== 0 || prototype.$Prototype !== this.realm.intrinsics.ObjectPrototype || prototype.$Extensible.mightNotBeTrue()) {
195 return false;
196 }
197
198 let foundConstructor = false;
199
200 for (let name of prototype.properties.keys()) if (name === "constructor" && HeapInspector.getPropertyValue(prototype, name) === prototype.originalConstructor) foundConstructor = true;else return false;
201
202 return foundConstructor;
203 }
204
205}
206
207exports.HeapInspector = HeapInspector;
208
209_defineProperty(HeapInspector, "_integrityDescriptors", {
210 "": {
211 writable: true,
212 configurable: true
213 },
214 preventExtensions: {
215 writable: true,
216 configurable: true
217 },
218 seal: {
219 writable: true,
220 configurable: false
221 },
222 freeze: {
223 writable: false,
224 configurable: false
225 }
226});
227//# sourceMappingURL=HeapInspector.js.map
\No newline at end of file