blob: 38b68b6ed74916ada516648160961a1398ba33e9 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Murdochc5610432016-08-08 18:44:38 +01005// Flags: --harmony-do-expressions --allow-natives-syntax
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006
7function returnValue(v) { return v; }
8function MyError() {}
9var global = this;
10
11function TestBasic() {
12 // Looping and lexical declarations
13 assertEquals(512, returnValue(do {
14 let n = 2;
15 for (let i = 0; i < 4; i++) n <<= 2;
16 }));
17
18 // Strings do the right thing
19 assertEquals("spooky halloween", returnValue(do {
20 "happy halloween".replace('happy', 'spooky');
21 }));
22
23 // Do expressions with no completion produce an undefined value
24 assertEquals(undefined, returnValue(do {}));
25 assertEquals(undefined, returnValue(do { var x = 99; }));
26 assertEquals(undefined, returnValue(do { function f() {}; }));
27 assertEquals(undefined, returnValue(do { let z = 33; }));
28
29 // Propagation of exception
30 assertThrows(function() {
31 (do {
32 throw new MyError();
33 "potatoes";
34 });
35 }, MyError);
36
37 assertThrows(function() {
38 return do {
39 throw new MyError();
40 "potatoes";
41 };
42 }, MyError);
43
44 // Return value within do-block overrides `return |do-expression|`
45 assertEquals("inner-return", (function() {
46 return "outer-return" + do {
47 return "inner-return";
48 "";
49 };
50 })());
51
52 var count = 0, n = 1;
53 // Breaking out |do-expression|
54 assertEquals(3, (function() {
55 for (var i = 0; i < 10; ++i) (count += 2 * do { if (i === 3) break; ++n });
56 return i;
57 })());
58 // (2 * 2) + (2 * 3) + (2 * 4)
59 assertEquals(18, count);
60
61 // Continue in |do-expression|
62 count = 0, n = 1;
63 assertEquals([1, 3, 5, 7, 9], (function() {
64 var values = [];
65 for (var i = 0; i < 10; ++i) {
66 count += 2 * (do {
67 if ((i & 1) === 0) continue;
68 values.push(i);
69 ++n;
70 }) + 1;
71 }
72 // (2*2) + 1 + (2*3) + 1 + (2*4) + 1 + (2*5) + 1 + (2*6) + 1
73 return values;
74 })());
75 assertEquals(count, 45);
76
77 assertThrows("(do { break; });", SyntaxError);
78 assertThrows("(do { continue; });", SyntaxError);
79
80 // Real-world use case for desugaring
81 var array = [1, 2, 3, 4, 5], iterable = [6, 7, 8,9];
82 assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], do {
83 for (var element of iterable) array.push(element);
84 array;
85 });
86
87 // Nested do-expressions
88 assertEquals(125, do { (do { (do { 5 * 5 * 5 }) }) });
89
90 // Directives are not honoured
91 (do {
92 "use strict";
93 foo = 80;
94 assertEquals(foo, 80);
95 });
96
97 // Non-empty operand stack testing
98 var O = {
99 method1() {
100 let x = 256;
101 return x + do {
102 for (var i = 0; i < 4; ++i) x += i;
103 } + 17;
104 },
105 method2() {
106 let x = 256;
107 this.reset();
108 return x + do {
109 for (var i = 0; i < this.length(); ++i) x += this.index() * 2;
110 };
111 },
112 _index: 0,
113 index() {
114 return ++this._index;
115 },
116 _length: 4,
117 length() { return this._length; },
118 reset() { this._index = 0; }
119 };
120 assertEquals(535, O["method" + do { 1 } + ""]());
121 assertEquals(532, O["method" + do { ({ valueOf() { return "2"; } }); }]());
122 assertEquals(532, O[
123 do { let s = ""; for (let c of "method") s += c; } + "2"]());
124}
125TestBasic();
126
127
128function TestDeoptimization1() {
129 function f(v) {
130 return 88 + do {
131 v.a * v.b + v.c;
132 };
133 }
134
135 var o1 = {};
136 o1.a = 10;
137 o1.b = 5;
138 o1.c = 50;
139
140 var o2 = {};
141 o2.c = 100;
142 o2.a = 10;
143 o2.b = 10;
144
145 assertEquals(188, f(o1));
146 assertEquals(188, f(o1));
147 %OptimizeFunctionOnNextCall(f);
148 assertEquals(188, f(o1));
149 assertOptimized(f);
150 assertEquals(288, f(o2));
151 assertUnoptimized(f);
152 assertEquals(288, f(o2));
153}
154TestDeoptimization1();
155
156
157function TestInParameterInitializers() {
158 var first_name = "George";
159 var last_name = "Jetson";
160 function fn1(name = do { first_name + " " + last_name }) {
161 return name;
162 }
163 assertEquals("George Jetson", fn1());
164
165 var _items = [1, 2, 3, NaN, 4, 5];
166 function fn2(items = do {
167 let items = [];
168 for (var el of _items) {
169 if (el !== el) {
170 items;
171 break;
172 }
173 items.push(el), items;
174 }
175 }) {
176 return items;
177 }
178 assertEquals([1, 2, 3], fn2());
179
180 function thrower() { throw new MyError(); }
181 function fn3(exception = do { try { thrower(); } catch (e) { e } }) {
182 return exception;
183 }
184 assertDoesNotThrow(fn3);
185 assertInstanceof(fn3(), MyError);
186
187 function fn4(exception = do { throw new MyError() }) {}
188 function catcher(fn) {
189 try {
190 fn();
191 assertUnreachable("fn() initializer should throw");
192 } catch (e) {
193 assertInstanceof(e, MyError);
194 }
195 }
196 catcher(fn4);
197}
198TestInParameterInitializers();
199
200
201function TestWithEval() {
202 (function sloppy1() {
203 assertEquals(do { eval("var x = 5"), x }, 5);
204 assertEquals(x, 5);
205 })();
206
207 assertThrows(function strict1() {
208 "use strict";
209 (do { eval("var x = 5"), x }, 5);
210 }, ReferenceError);
211
212 assertThrows(function strict2() {
213 (do { eval("'use strict'; var x = 5"), x }, 5);
214 }, ReferenceError);
215}
216TestWithEval();
217
218
219function TestHoisting() {
220 (do { var a = 1; });
221 assertEquals(a, 1);
222 assertEquals(global.a, undefined);
223
224 (do {
225 for (let it of [1, 2, 3, 4, 5]) {
226 var b = it;
227 }
228 });
229 assertEquals(b, 5);
230 assertEquals(global.b, undefined);
231
232 {
233 let x = 1
234
235 // TODO(caitp): ensure VariableStatements in |do-expressions| in parameter
236 // initializers, are evaluated in the same VariableEnvironment as they would
237 // be for eval().
238 // function f1(a = do { var x = 2 }, b = x) { return b }
239 // assertEquals(1, f1())
240
241 // function f2(a = x, b = do { var x = 2 }) { return a }
242 // assertEquals(1, f2())
243
244 function f3({a = do { var x = 2 }, b = x}) { return b }
245 assertEquals(2, f3({}))
246
247 function f4({a = x, b = do { var x = 2 }}) { return b }
248 assertEquals(undefined, f4({}))
249
250 function f5(a = do { var y = 0 }) {}
251 assertThrows(() => y, ReferenceError)
252 }
253
254 // TODO(caitp): Always block-scope function declarations in |do| expressions
255 //(do {
256 // assertEquals(true, inner_func());
257 // function inner_func() { return true; }
258 //});
259 //assertThrows(function() { return innerFunc(); }, ReferenceError);
260}
261TestHoisting();
262
263
264// v8:4661
265
266function tryFinallySimple() { (do { try {} finally {} }); }
267tryFinallySimple();
268tryFinallySimple();
269tryFinallySimple();
270tryFinallySimple();
271
272var finallyRanCount = 0;
273function tryFinallyDoExpr() {
274 return (do {
275 try {
276 throw "BOO";
277 } catch (e) {
278 "Caught: " + e + " (" + finallyRanCount + ")"
279 } finally {
280 ++finallyRanCount;
281 }
282 });
283}
284assertEquals("Caught: BOO (0)", tryFinallyDoExpr());
285assertEquals(1, finallyRanCount);
286assertEquals("Caught: BOO (1)", tryFinallyDoExpr());
287assertEquals(2, finallyRanCount);
288assertEquals("Caught: BOO (2)", tryFinallyDoExpr());
289assertEquals(3, finallyRanCount);
290assertEquals("Caught: BOO (3)", tryFinallyDoExpr());
291assertEquals(4, finallyRanCount);
292
293
294function TestOSR() {
295 var numbers = do {
296 let nums = [];
297 for (let i = 0; i < 1000; ++i) {
298 let value = (Math.random() * 100) | 0;
299 nums.push(value === 0 ? 1 : value), nums;
300 }
301 };
302 assertEquals(numbers.length, 1000);
303}
304
305for (var i = 0; i < 64; ++i) TestOSR();