1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.HeapInspector = void 0;
|
7 |
|
8 | var _realm = require("../realm.js");
|
9 |
|
10 | var _index = require("../methods/index.js");
|
11 |
|
12 | var _index2 = require("../values/index.js");
|
13 |
|
14 | var _singletons = require("../singletons.js");
|
15 |
|
16 | var _invariant = _interopRequireDefault(require("../invariant.js"));
|
17 |
|
18 | var _logger = require("./logger.js");
|
19 |
|
20 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
21 |
|
22 | 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; }
|
23 |
|
24 | class 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) {
|
39 |
|
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;
|
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 |
|
82 | return true;
|
83 | }
|
84 | }
|
85 |
|
86 | if (val.isIntrinsic()) {
|
87 | return false;
|
88 | }
|
89 |
|
90 | return val instanceof _index2.PrimitiveValue;
|
91 | }
|
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;
|
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 |
|
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.");
|
130 | }
|
131 |
|
132 |
|
133 | return !desc.writable && !desc.enumerable && desc.configurable === targetDescriptor.configurable && val.hasDefaultLength();
|
134 | }
|
135 |
|
136 | if (key === "name") {
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
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 | }
|
145 |
|
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 | }
|
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 |
|
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 |
|
207 | exports.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 |
|
\ | No newline at end of file |