[JSC] Clean up Object.entries implementation
[WebKit-https.git] / JSTests / microbenchmarks / regexp-prototype-split-observable-side-effects.js
1 //@ runNoFTL
2
3 function assert(testedValue, msg) {
4     if (!testedValue)
5         throw Error(msg);
6 }
7
8 // Subclass with overridden [@@species]: Testing ES6 21.2.5.11: 4. Let C be ? SpeciesConstructor(rx, %RegExp%).
9 (function () {
10     let accesses = [];
11     class TestRegExp extends RegExp { }
12     Object.defineProperty(TestRegExp, Symbol.species, {
13         value: function() {
14             accesses.push(Symbol.species.toString());
15             return /it/y;
16         }
17     });
18     let obj = new TestRegExp(/it/);
19     let errorStr;
20
21     assert(accesses == "", "unexpected call to overridden props");
22     let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
23     assert(accesses == "Symbol(Symbol.species)", "Property accesses do not match expectation");
24     assert(result == "spl,me", "Unexpected result");
25 })();
26
27 // RegExp subclass with constructor: Testing ES6 21.2.5.11: 4. Let C be ? SpeciesConstructor(rx, %RegExp%).
28 (function () {
29     let accesses = [];
30     class TestRegExp extends RegExp {
31         constructor(str, flags) {
32             super(str, flags);
33             accesses.push("constructor");
34         }
35     }
36     let obj = new TestRegExp("it");
37
38     assert(accesses == "constructor", "unexpected call to overridden props");
39     let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
40     assert(accesses == "constructor,constructor", "Property accesses do not match expectation");
41     assert(result == "spl,me", "Unexpected result");
42 })();
43
44 // An object with species constructor: Testing ES6 21.2.5.11: 4. Let C be ? SpeciesConstructor(rx, %RegExp%).
45 (function () {
46     let accesses = [];
47     let obj = { constructor: {} };
48     obj.constructor[Symbol.species] = function() {
49         accesses.push("constructor");
50         return /it/y;
51     };
52
53     assert(accesses == "", "unexpected call to overridden props");
54     let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
55     assert(accesses == "constructor", "Property accesses do not match expectation");
56     assert(result == "spl,me", "Unexpected result");
57 })();
58
59 // RegExp object with overridden flags: Testing ES6 21.2.5.11: 5. Let flags be ? ToString(? Get(rx, "flags")).
60 (function () {
61     let flags = [ "flags", "global", "ignoreCase", "multiline", "sticky", "unicode" ];
62     let flagValues = [ "", false, false, false, false, false ];
63     for (let index in flags) {
64         (function(flag, flagValue) {
65             let accesses = [];
66             let obj = /it/;
67             Object.defineProperty(obj, flag, {
68                 get: function() {
69                     accesses.push(flag);
70                     passed = true;
71                     return flagValue;
72                 }
73             });
74
75             assert(accesses == "", "unexpected call to overridden props");
76             let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
77             assert(accesses == flag, "Property accesses do not match expectation");
78             assert(result == "spl,me", "Unexpected result");
79         }) (flags[index], flagValues[index]);
80     }
81 })();
82
83 // RegExp subclass with overridden flags in subclass method: Testing ES6 21.2.5.11: 5. Let flags be ? ToString(? Get(rx, "flags")).
84 (function () {
85     let flags = [ "flags", "global", "ignoreCase", "multiline", "sticky", "unicode" ];
86     let flagValues = [ "", false, false, false, false, false ];
87     for (let index in flags) {
88         (function(flag, flagValue) {
89             let accesses = [];
90             class TestRegExp extends RegExp {
91                 get [flag]() {
92                     accesses.push(flag);
93                     return flagValue;
94                 }
95             };
96             let obj = new TestRegExp(/it/);
97
98             assert(accesses == "", "unexpected call to overridden props");
99             let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
100             assert(accesses == flag, "Property accesses do not match expectation");
101             assert(result == "spl,me", "Unexpected result");
102
103         }) (flags[index], flagValues[index]);
104     }
105 })();
106
107 // RegExp subclass with overridden flags using Object.defineProperty: Testing ES6 21.2.5.11: 5. Let flags be ? ToString(? Get(rx, "flags")).
108 (function () {
109     let flags = [ "flags", "global", "ignoreCase", "multiline", "sticky", "unicode" ];
110     let flagValues = [ "", false, false, false, false, false ];
111     for (let index in flags) {
112         (function(flag, flagValue) {
113             let accesses = [];
114             class TestRegExp extends RegExp { };
115             let obj = new TestRegExp(/it/);
116
117             Object.defineProperty(obj, flag, {
118                 get: function() {
119                     accesses.push(flag);
120                     return flagValue;
121                 }
122             });
123
124             assert(accesses == "", "unexpected call to overridden props");
125             let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
126             assert(accesses == flag, "Property accesses do not match expectation");
127             assert(result == "spl,me", "Unexpected result");
128
129         }) (flags[index], flagValues[index]);
130     }
131 })();
132
133 // Any object with species constructor: Testing ES6 21.2.5.11: 5. Let flags be ? ToString(? Get(rx, "flags")).
134 (function () {
135     let accesses = [];
136     let obj = { constructor: {} };
137     obj.constructor[Symbol.species] = function() {
138         accesses.push("constructor");
139         return /it/y;
140     };
141
142     Object.defineProperty(obj, "flags", {
143         get: function() {
144             accesses.push("flags");
145             return "";
146         }
147     });
148
149     assert(accesses == "", "unexpected call to overridden props");
150     let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
151     assert(accesses == "flags,constructor", "Property accesses do not match expectation");
152     assert(result == "spl,me", "Unexpected result");
153 })();
154
155 // Any object with custom prototype: Testing ES6 21.2.5.11: 5. Let flags be ? ToString(? Get(rx, "flags")).
156 (function () {
157     let accesses = [];
158     let TestRegExpProto = {
159         get flags() {
160             accesses.push("flags");
161             return "";
162         },
163         toString() {
164             accesses.push("toString");
165             return this._regex.toString();
166         },
167         get source() {
168             accesses.push("source");
169             return this._regex.source;
170         }
171     }
172     TestRegExpProto.__proto__ = RegExp.prototype;
173
174     let TestRegExp = function(regex) {
175         accesses.push("constructor");
176         this._regex = new RegExp(regex);
177     }
178     TestRegExp.prototype = TestRegExpProto;
179     TestRegExpProto.constructor = TestRegExp;
180
181     let obj = new TestRegExp(/it/);
182
183     assert(accesses == "constructor", "unexpected call to overridden props");
184     let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
185     assert(accesses == "constructor,flags,source", "Property accesses do not match expectation");
186     assert(result == "spl,me", "Unexpected result");
187 })();
188
189 // 2 levels of subclasses: Testing ES6 21.2.5.11: 5. Let flags be ? ToString(? Get(rx, "flags")).
190 (function () {
191     let accesses = [];
192
193     class RegExpB extends RegExp {
194         get flags() {
195             accesses.push("flags");
196             return "";
197         }
198     }
199     class RegExpC extends RegExpB { }
200
201     assert(RegExpB.__proto__ == RegExp);
202     assert(RegExpC.__proto__ == RegExpB);
203
204     let obj = new RegExpC(/it/);
205
206     assert(accesses == "", "unexpected call to overridden props");
207     let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
208     assert(accesses == "flags", "Property accesses do not match expectation");
209     assert(result == "spl,me", "Unexpected result");
210 })();
211
212 // 2 levels of subclasses with substituted prototype before instantiation: Testing ES6 21.2.5.11: 5. Let flags be ? ToString(? Get(rx, "flags")).
213 (function () {
214     let accesses = [];
215
216     class B extends RegExp { }
217     class C extends B { }
218
219     assert(B.__proto__ === RegExp);
220     assert(C.__proto__ === B);
221     assert(B.prototype.__proto__ === RegExp.prototype);
222     assert(C.prototype.__proto__ === B.prototype);
223
224     let X = function () {}
225     Object.defineProperty(X.prototype, "flags", {
226         get: function() {
227             accesses.push("flags");
228             return "";
229         }
230     });
231     Object.defineProperty(X.prototype, "exec", {
232         value: function(str) {
233             accesses.push("exec");
234             var matchResult = /it/y.exec(str.substr(this.lastIndex));
235             if (matchResult)
236                 this.lastIndex += 2; // length of "it".
237             return matchResult;
238         }
239     });
240
241     // Monkey with the prototype chain before instantiating C.
242     X.__proto__ = RegExp;
243     X.prototype.__proto__ = RegExp.prototype;
244     C.__proto__ = X;
245     C.prototype.__proto__ = X.prototype;
246
247     assert(X.__proto__ === RegExp);
248     assert(C.__proto__ === X);
249     assert(X.prototype.__proto__ === RegExp.prototype);
250     assert(C.prototype.__proto__ === X.prototype);
251
252     let obj = new C;
253
254     assert(accesses == "", "unexpected call to overridden props");
255     let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
256     assert(accesses == "flags,exec,exec,exec,exec,exec,exec", "Property accesses do not match expectation");
257     assert(result == "spl,me", "Unexpected result");
258 })();
259
260 // 2 levels of subclasses with substituted prototype after instantiation: Testing ES6 21.2.5.11: 5. Let flags be ? ToString(? Get(rx, "flags")).
261 (function () {
262     let accesses = [];
263
264     class B extends RegExp { }
265     class C extends B { }
266
267     assert(B.__proto__ === RegExp);
268     assert(C.__proto__ === B);
269     assert(B.prototype.__proto__ === RegExp.prototype);
270     assert(C.prototype.__proto__ === B.prototype);
271
272     let X = function () {}
273     Object.defineProperty(X.prototype, "flags", {
274         get: function() {
275             accesses.push("flags");
276             return "";
277         }
278     });
279     Object.defineProperty(X.prototype, "exec", {
280         value: function(str) {
281             accesses.push("exec");
282             var matchResult = /it/y.exec(str.substr(this.lastIndex));
283             if (matchResult)
284                 this.lastIndex += 2; // length of "it".
285             return matchResult;
286         }
287     });
288
289     // Instantiate C before monkeying with the prototype chain.
290     let obj = new C();
291
292     X.__proto__ = RegExp;
293     X.prototype.__proto__ = RegExp.prototype;
294     C.__proto__ = X;
295     C.prototype.__proto__ = X.prototype;
296
297     assert(X.__proto__ === RegExp);
298     assert(C.__proto__ === X);
299     assert(X.prototype.__proto__ === RegExp.prototype);
300     assert(C.prototype.__proto__ === X.prototype);
301
302     assert(accesses == "", "unexpected call to overridden props");
303     let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
304     assert(accesses == "flags,exec,exec,exec,exec,exec,exec", "Property accesses do not match expectation");
305     assert(result == "spl,me", "Unexpected result");
306 })();
307
308 // 2 levels of subclasses with proxied prototype: Testing ES6 21.2.5.11: 5. Let flags be ? ToString(? Get(rx, "flags")).
309 (function () {
310     let accesses = [];
311
312     class B extends RegExp { };
313
314     assert(B.__proto__ === RegExp);
315     assert(B.prototype.__proto__ === RegExp.prototype);
316
317     let proxy = new Proxy(RegExp.prototype, {
318         get: function(obj, prop) {
319             accesses.push(prop.toString());
320             if (prop === "exec") {
321                 return function(str) {
322                     accesses.push("in_exec");
323                     var matchResult = /it/y.exec(str.substr(this.lastIndex));
324                     if (matchResult)
325                         this.lastIndex += 2; // length of "it".
326                     return matchResult;
327                 }
328             }
329             return obj[prop];
330         }
331     });
332     B.prototype.__proto__ = proxy;
333
334     let obj = new B();
335
336     assert(accesses == "", "unexpected call to overridden props");
337     let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
338     assert(accesses == "flags,Symbol(Symbol.match),exec,in_exec,exec,in_exec,exec,in_exec,exec,in_exec,exec,in_exec,exec,in_exec", "Property accesses do not match expectation");
339     assert(result == "spl,me", "Unexpected result");
340 })();
341
342 // RegExp subclass with overridden exec: Testing ES6 21.2.5.11: 19.b. Let z be ? RegExpExec(splitter, S).
343 (function () {
344     let accesses = [];
345     class TestRegExp extends RegExp {
346         exec(str) {
347             accesses.push("exec");
348             return RegExp.prototype.exec.call(this, str);
349         }
350     };
351     let obj = new TestRegExp(/it/);
352
353     assert(accesses == "", "unexpected call to overridden props");
354     let result = RegExp.prototype[Symbol.split].call(obj, "splitme");
355     assert(accesses == "exec,exec,exec,exec,exec,exec", "Property accesses do not match expectation");
356     assert(result == "spl,me", "Unexpected result");
357 })();
358
359 // Proxied RegExp observing every get.
360 (function () {
361     let accesses = [];
362     let regexp = new RegExp(/it/);
363     let proxy = new Proxy(regexp, {
364         get(obj, prop) {
365             accesses.push(prop.toString());
366             return obj[prop];
367         }
368     });
369
370     assert(accesses == "", "unexpected call to overridden props");
371     let result = RegExp.prototype[Symbol.split].call(proxy, "splitme");
372     // Note: @@split creates a new instance of the RegExp using its @@species, and performs
373     // the split operation with that new instance. Hence, the proxy is only able to observe
374     // gets up to the creation of the new instance.
375     assert(accesses == "constructor,flags,Symbol(Symbol.match),source",
376         "Proxy not able to observe some gets");
377     assert(result == "spl,me", "Unexpected result");
378 })();
379
380 // Proxied RegExp (without @@match) observing every get.
381 // This is to force the RegExp @species constructor to access source.
382 (function () {
383     let accesses = [];
384     let regexp = new RegExp(/it/);
385     let proxy = new Proxy(regexp, {
386         get(obj, prop) {
387             accesses.push(prop.toString());
388             if (prop == Symbol.match)
389                 return undefined;
390             return obj[prop];
391         }
392     });
393
394     assert(accesses == "", "unexpected call to overridden props");
395     let result = RegExp.prototype[Symbol.split].call(proxy, "splitme");
396     // Note: @@split creates a new instance of the RegExp using its @@species, and performs
397     // the split operation with that new instance. Hence, the proxy is only able to observe
398     // gets up to the creation of the new instance.
399     assert(accesses == "constructor,flags,Symbol(Symbol.match),Symbol(Symbol.toPrimitive),toString,source,flags",
400         "Proxy not able to observe some gets");
401     // The new instance of the RegExp would have been constructed with the pattern from
402     // the proxy toString() i.e. "\/lt\/" instead of source, because the proxy is an
403     // object without a [@@match] property.
404     assert(result == "splitme", "Unexpected result");
405 })();
406