OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Flags: --allow-natives-syntax --harmony-tailcalls | 5 // Flags: --allow-natives-syntax --harmony-explicit-tailcalls |
6 "use strict"; | |
7 | 6 |
8 Error.prepareStackTrace = (error,stack) => { | 7 Error.prepareStackTrace = (error,stack) => { |
9 error.strace = stack; | 8 error.strace = stack; |
10 return error.message + "\n at " + stack.join("\n at "); | 9 return error.message + "\n at " + stack.join("\n at "); |
11 } | 10 } |
12 | 11 |
13 | 12 |
14 function CheckStackTrace(expected) { | 13 function CheckStackTrace(expected) { |
15 var e = new Error(); | 14 var e = new Error(); |
16 e.stack; // prepare stack trace | 15 e.stack; // prepare stack trace |
(...skipping 15 matching lines...) Expand all Loading... |
32 } | 31 } |
33 | 32 |
34 | 33 |
35 // Tail call when caller does not have an arguments adaptor frame. | 34 // Tail call when caller does not have an arguments adaptor frame. |
36 (function() { | 35 (function() { |
37 // Caller and callee have same number of arguments. | 36 // Caller and callee have same number of arguments. |
38 function f1(a) { | 37 function f1(a) { |
39 CheckStackTrace([f1, test]); | 38 CheckStackTrace([f1, test]); |
40 return 10 + a; | 39 return 10 + a; |
41 } | 40 } |
42 function g1(a) { return f1(2); } | 41 function g1(a) { return continue f1(2); } |
43 | 42 |
44 // Caller has more arguments than callee. | 43 // Caller has more arguments than callee. |
45 function f2(a) { | 44 function f2(a) { |
46 CheckStackTrace([f2, test]); | 45 CheckStackTrace([f2, test]); |
47 return 10 + a; | 46 return 10 + a; |
48 } | 47 } |
49 function g2(a, b, c) { return f2(2); } | 48 function g2(a, b, c) { return continue f2(2); } |
50 | 49 |
51 // Caller has less arguments than callee. | 50 // Caller has less arguments than callee. |
52 function f3(a, b, c) { | 51 function f3(a, b, c) { |
53 CheckStackTrace([f3, test]); | 52 CheckStackTrace([f3, test]); |
54 return 10 + a + b + c; | 53 return 10 + a + b + c; |
55 } | 54 } |
56 function g3(a) { return f3(2, 3, 4); } | 55 function g3(a) { return continue f3(2, 3, 4); } |
57 | 56 |
58 // Callee has arguments adaptor frame. | 57 // Callee has arguments adaptor frame. |
59 function f4(a, b, c) { | 58 function f4(a, b, c) { |
60 CheckStackTrace([f4, test]); | 59 CheckStackTrace([f4, test]); |
61 return 10 + a; | 60 return 10 + a; |
62 } | 61 } |
63 function g4(a) { return f4(2); } | 62 function g4(a) { return continue f4(2); } |
64 | 63 |
65 function test() { | 64 function test() { |
66 assertEquals(12, g1(1)); | 65 assertEquals(12, g1(1)); |
67 assertEquals(12, g2(1, 2, 3)); | 66 assertEquals(12, g2(1, 2, 3)); |
68 assertEquals(19, g3(1)); | 67 assertEquals(19, g3(1)); |
69 assertEquals(12, g4(1)); | 68 assertEquals(12, g4(1)); |
70 } | 69 } |
71 test(); | 70 test(); |
72 test(); | 71 test(); |
73 %OptimizeFunctionOnNextCall(test); | 72 %OptimizeFunctionOnNextCall(test); |
74 test(); | 73 test(); |
75 })(); | 74 })(); |
76 | 75 |
77 | 76 |
78 // Tail call when caller has an arguments adaptor frame. | 77 // Tail call when caller has an arguments adaptor frame. |
79 (function() { | 78 (function() { |
80 // Caller and callee have same number of arguments. | 79 // Caller and callee have same number of arguments. |
81 function f1(a) { | 80 function f1(a) { |
82 CheckStackTrace([f1, test]); | 81 CheckStackTrace([f1, test]); |
83 return 10 + a; | 82 return 10 + a; |
84 } | 83 } |
85 function g1(a) { return f1(2); } | 84 function g1(a) { return continue f1(2); } |
86 | 85 |
87 // Caller has more arguments than callee. | 86 // Caller has more arguments than callee. |
88 function f2(a) { | 87 function f2(a) { |
89 CheckStackTrace([f2, test]); | 88 CheckStackTrace([f2, test]); |
90 return 10 + a; | 89 return 10 + a; |
91 } | 90 } |
92 function g2(a, b, c) { return f2(2); } | 91 function g2(a, b, c) { return continue f2(2); } |
93 | 92 |
94 // Caller has less arguments than callee. | 93 // Caller has less arguments than callee. |
95 function f3(a, b, c) { | 94 function f3(a, b, c) { |
96 CheckStackTrace([f3, test]); | 95 CheckStackTrace([f3, test]); |
97 return 10 + a + b + c; | 96 return 10 + a + b + c; |
98 } | 97 } |
99 function g3(a) { return f3(2, 3, 4); } | 98 function g3(a) { return continue f3(2, 3, 4); } |
100 | 99 |
101 // Callee has arguments adaptor frame. | 100 // Callee has arguments adaptor frame. |
102 function f4(a, b, c) { | 101 function f4(a, b, c) { |
103 CheckStackTrace([f4, test]); | 102 CheckStackTrace([f4, test]); |
104 return 10 + a; | 103 return 10 + a; |
105 } | 104 } |
106 function g4(a) { return f4(2); } | 105 function g4(a) { return continue f4(2); } |
107 | 106 |
108 function test() { | 107 function test() { |
109 assertEquals(12, g1()); | 108 assertEquals(12, g1()); |
110 assertEquals(12, g2()); | 109 assertEquals(12, g2()); |
111 assertEquals(19, g3()); | 110 assertEquals(19, g3()); |
112 assertEquals(12, g4()); | 111 assertEquals(12, g4()); |
113 } | 112 } |
114 test(); | 113 test(); |
115 test(); | 114 test(); |
116 %OptimizeFunctionOnNextCall(test); | 115 %OptimizeFunctionOnNextCall(test); |
117 test(); | 116 test(); |
118 })(); | 117 })(); |
119 | 118 |
120 | 119 |
121 // Tail call bound function when caller does not have an arguments | 120 // Tail call bound function when caller does not have an arguments |
122 // adaptor frame. | 121 // adaptor frame. |
123 (function() { | 122 (function() { |
124 // Caller and callee have same number of arguments. | 123 // Caller and callee have same number of arguments. |
125 function f1(a) { | 124 function f1(a) { |
126 assertEquals(153, this.a); | 125 assertEquals(153, this.a); |
127 CheckStackTrace([f1, test]); | 126 CheckStackTrace([f1, test]); |
128 return 10 + a; | 127 return 10 + a; |
129 } | 128 } |
130 var b1 = f1.bind({a: 153}); | 129 var b1 = f1.bind({a: 153}); |
131 function g1(a) { return b1(2); } | 130 function g1(a) { return continue b1(2); } |
132 | 131 |
133 // Caller has more arguments than callee. | 132 // Caller has more arguments than callee. |
134 function f2(a) { | 133 function f2(a) { |
135 assertEquals(153, this.a); | 134 assertEquals(153, this.a); |
136 CheckStackTrace([f2, test]); | 135 CheckStackTrace([f2, test]); |
137 return 10 + a; | 136 return 10 + a; |
138 } | 137 } |
139 var b2 = f2.bind({a: 153}); | 138 var b2 = f2.bind({a: 153}); |
140 function g2(a, b, c) { return b2(2); } | 139 function g2(a, b, c) { return continue b2(2); } |
141 | 140 |
142 // Caller has less arguments than callee. | 141 // Caller has less arguments than callee. |
143 function f3(a, b, c) { | 142 function f3(a, b, c) { |
144 assertEquals(153, this.a); | 143 assertEquals(153, this.a); |
145 CheckStackTrace([f3, test]); | 144 CheckStackTrace([f3, test]); |
146 return 10 + a + b + c; | 145 return 10 + a + b + c; |
147 } | 146 } |
148 var b3 = f3.bind({a: 153}); | 147 var b3 = f3.bind({a: 153}); |
149 function g3(a) { return b3(2, 3, 4); } | 148 function g3(a) { return continue b3(2, 3, 4); } |
150 | 149 |
151 // Callee has arguments adaptor frame. | 150 // Callee has arguments adaptor frame. |
152 function f4(a, b, c) { | 151 function f4(a, b, c) { |
153 assertEquals(153, this.a); | 152 assertEquals(153, this.a); |
154 CheckStackTrace([f4, test]); | 153 CheckStackTrace([f4, test]); |
155 return 10 + a; | 154 return 10 + a; |
156 } | 155 } |
157 var b4 = f4.bind({a: 153}); | 156 var b4 = f4.bind({a: 153}); |
158 function g4(a) { return b4(2); } | 157 function g4(a) { return continue b4(2); } |
159 | 158 |
160 function test() { | 159 function test() { |
161 assertEquals(12, g1(1)); | 160 assertEquals(12, g1(1)); |
162 assertEquals(12, g2(1, 2, 3)); | 161 assertEquals(12, g2(1, 2, 3)); |
163 assertEquals(19, g3(1)); | 162 assertEquals(19, g3(1)); |
164 assertEquals(12, g4(1)); | 163 assertEquals(12, g4(1)); |
165 } | 164 } |
166 test(); | 165 test(); |
167 test(); | 166 test(); |
168 %OptimizeFunctionOnNextCall(test); | 167 %OptimizeFunctionOnNextCall(test); |
169 test(); | 168 test(); |
170 })(); | 169 })(); |
171 | 170 |
172 | 171 |
173 // Tail call bound function when caller has an arguments adaptor frame. | 172 // Tail call bound function when caller has an arguments adaptor frame. |
174 (function() { | 173 (function() { |
175 // Caller and callee have same number of arguments. | 174 // Caller and callee have same number of arguments. |
176 function f1(a) { | 175 function f1(a) { |
177 assertEquals(153, this.a); | 176 assertEquals(153, this.a); |
178 CheckStackTrace([f1, test]); | 177 CheckStackTrace([f1, test]); |
179 return 10 + a; | 178 return 10 + a; |
180 } | 179 } |
181 var b1 = f1.bind({a: 153}); | 180 var b1 = f1.bind({a: 153}); |
182 function g1(a) { return b1(2); } | 181 function g1(a) { return continue b1(2); } |
183 | 182 |
184 // Caller has more arguments than callee. | 183 // Caller has more arguments than callee. |
185 function f2(a) { | 184 function f2(a) { |
186 assertEquals(153, this.a); | 185 assertEquals(153, this.a); |
187 CheckStackTrace([f2, test]); | 186 CheckStackTrace([f2, test]); |
188 return 10 + a; | 187 return 10 + a; |
189 } | 188 } |
190 var b2 = f2.bind({a: 153}); | 189 var b2 = f2.bind({a: 153}); |
191 function g2(a, b, c) { return b2(2); } | 190 function g2(a, b, c) { return continue b2(2); } |
192 | 191 |
193 // Caller has less arguments than callee. | 192 // Caller has less arguments than callee. |
194 function f3(a, b, c) { | 193 function f3(a, b, c) { |
195 assertEquals(153, this.a); | 194 assertEquals(153, this.a); |
196 CheckStackTrace([f3, test]); | 195 CheckStackTrace([f3, test]); |
197 return 10 + a + b + c; | 196 return 10 + a + b + c; |
198 } | 197 } |
199 var b3 = f3.bind({a: 153}); | 198 var b3 = f3.bind({a: 153}); |
200 function g3(a) { return b3(2, 3, 4); } | 199 function g3(a) { return continue b3(2, 3, 4); } |
201 | 200 |
202 // Callee has arguments adaptor frame. | 201 // Callee has arguments adaptor frame. |
203 function f4(a, b, c) { | 202 function f4(a, b, c) { |
204 assertEquals(153, this.a); | 203 assertEquals(153, this.a); |
205 CheckStackTrace([f4, test]); | 204 CheckStackTrace([f4, test]); |
206 return 10 + a; | 205 return 10 + a; |
207 } | 206 } |
208 var b4 = f4.bind({a: 153}); | 207 var b4 = f4.bind({a: 153}); |
209 function g4(a) { return b4(2); } | 208 function g4(a) { return continue b4(2); } |
210 | 209 |
211 function test() { | 210 function test() { |
212 assertEquals(12, g1()); | 211 assertEquals(12, g1()); |
213 assertEquals(12, g2()); | 212 assertEquals(12, g2()); |
214 assertEquals(19, g3()); | 213 assertEquals(19, g3()); |
215 assertEquals(12, g4()); | 214 assertEquals(12, g4()); |
216 } | 215 } |
217 test(); | 216 test(); |
218 test(); | 217 test(); |
219 %OptimizeFunctionOnNextCall(test); | 218 %OptimizeFunctionOnNextCall(test); |
220 test(); | 219 test(); |
221 })(); | 220 })(); |
222 | 221 |
223 | 222 |
224 // Tail calling via various expressions. | 223 // Tail calling via various expressions. |
225 (function() { | 224 (function() { |
226 function g1(a) { | 225 function g1(a) { |
227 return f([f, g1, test], false) || f([f, test], true); | 226 return continue f([f, g1, test], false) || f([f, test], true); |
228 } | 227 } |
229 | 228 |
230 function g2(a) { | 229 function g2(a) { |
231 return f([f, g2, test], true) && f([f, test], true); | 230 return continue f([f, g2, test], true) && f([f, test], true); |
232 } | 231 } |
233 | 232 |
234 function g3(a) { | 233 function g3(a) { |
235 return f([f, g3, test], 13), f([f, test], 153); | 234 return continue f([f, g3, test], 13), f([f, test], 153); |
236 } | 235 } |
237 | 236 |
238 function test() { | 237 function test() { |
239 assertEquals(true, g1()); | 238 assertEquals(true, g1()); |
240 assertEquals(true, g2()); | 239 assertEquals(true, g2()); |
241 assertEquals(153, g3()); | 240 assertEquals(153, g3()); |
242 } | 241 } |
243 test(); | 242 test(); |
244 test(); | 243 test(); |
245 %OptimizeFunctionOnNextCall(test); | 244 %OptimizeFunctionOnNextCall(test); |
(...skipping 11 matching lines...) Expand all Loading... |
257 f_153([f_153, tc1, test]); | 256 f_153([f_153, tc1, test]); |
258 } | 257 } |
259 } | 258 } |
260 | 259 |
261 function tc2(a) { | 260 function tc2(a) { |
262 try { | 261 try { |
263 f_153([f_153, tc2, test]); | 262 f_153([f_153, tc2, test]); |
264 throw new Error("boom"); | 263 throw new Error("boom"); |
265 } catch(e) { | 264 } catch(e) { |
266 f_153([f_153, tc2, test]); | 265 f_153([f_153, tc2, test]); |
267 return f_153([f_153, test]); | 266 return continue f_153([f_153, test]); |
268 } | 267 } |
269 } | 268 } |
270 | 269 |
271 function tc3(a) { | 270 function tc3(a) { |
272 try { | 271 try { |
273 f_153([f_153, tc3, test]); | 272 f_153([f_153, tc3, test]); |
274 throw new Error("boom"); | 273 throw new Error("boom"); |
275 } catch(e) { | 274 } catch(e) { |
276 f_153([f_153, tc3, test]); | 275 f_153([f_153, tc3, test]); |
277 } | 276 } |
278 f_153([f_153, tc3, test]); | 277 f_153([f_153, tc3, test]); |
279 return f_153([f_153, test]); | 278 return continue f_153([f_153, test]); |
280 } | 279 } |
281 | 280 |
282 function test() { | 281 function test() { |
283 assertEquals(153, tc1()); | 282 assertEquals(153, tc1()); |
284 assertEquals(153, tc2()); | 283 assertEquals(153, tc2()); |
285 assertEquals(153, tc3()); | 284 assertEquals(153, tc3()); |
286 } | 285 } |
287 test(); | 286 test(); |
288 test(); | 287 test(); |
289 %OptimizeFunctionOnNextCall(test); | 288 %OptimizeFunctionOnNextCall(test); |
(...skipping 11 matching lines...) Expand all Loading... |
301 f_153([f_153, tf1, test]); | 300 f_153([f_153, tf1, test]); |
302 } | 301 } |
303 } | 302 } |
304 | 303 |
305 function tf2(a) { | 304 function tf2(a) { |
306 try { | 305 try { |
307 f_153([f_153, tf2, test]); | 306 f_153([f_153, tf2, test]); |
308 throw new Error("boom"); | 307 throw new Error("boom"); |
309 } finally { | 308 } finally { |
310 f_153([f_153, tf2, test]); | 309 f_153([f_153, tf2, test]); |
311 return f_153([f_153, test]); | 310 return continue f_153([f_153, test]); |
312 } | 311 } |
313 } | 312 } |
314 | 313 |
315 function tf3(a) { | 314 function tf3(a) { |
316 try { | 315 try { |
317 f_153([f_153, tf3, test]); | 316 f_153([f_153, tf3, test]); |
318 } finally { | 317 } finally { |
319 f_153([f_153, tf3, test]); | 318 f_153([f_153, tf3, test]); |
320 } | 319 } |
321 return f_153([f_153, test]); | 320 return continue f_153([f_153, test]); |
322 } | 321 } |
323 | 322 |
324 function test() { | 323 function test() { |
325 assertEquals(153, tf1()); | 324 assertEquals(153, tf1()); |
326 assertEquals(153, tf2()); | 325 assertEquals(153, tf2()); |
327 assertEquals(153, tf3()); | 326 assertEquals(153, tf3()); |
328 } | 327 } |
329 test(); | 328 test(); |
330 test(); | 329 test(); |
331 %OptimizeFunctionOnNextCall(test); | 330 %OptimizeFunctionOnNextCall(test); |
(...skipping 26 matching lines...) Expand all Loading... |
358 } | 357 } |
359 | 358 |
360 function tcf3(a) { | 359 function tcf3(a) { |
361 try { | 360 try { |
362 f_153([f_153, tcf3, test]); | 361 f_153([f_153, tcf3, test]); |
363 throw new Error("boom"); | 362 throw new Error("boom"); |
364 } catch(e) { | 363 } catch(e) { |
365 f_153([f_153, tcf3, test]); | 364 f_153([f_153, tcf3, test]); |
366 } finally { | 365 } finally { |
367 f_153([f_153, tcf3, test]); | 366 f_153([f_153, tcf3, test]); |
368 return f_153([f_153, test]); | 367 return continue f_153([f_153, test]); |
369 } | 368 } |
370 } | 369 } |
371 | 370 |
372 function tcf4(a) { | 371 function tcf4(a) { |
373 try { | 372 try { |
374 f_153([f_153, tcf4, test]); | 373 f_153([f_153, tcf4, test]); |
375 throw new Error("boom"); | 374 throw new Error("boom"); |
376 } catch(e) { | 375 } catch(e) { |
377 f_153([f_153, tcf4, test]); | 376 f_153([f_153, tcf4, test]); |
378 } finally { | 377 } finally { |
379 f_153([f_153, tcf4, test]); | 378 f_153([f_153, tcf4, test]); |
380 } | 379 } |
381 return f_153([f_153, test]); | 380 return continue f_153([f_153, test]); |
382 } | 381 } |
383 | 382 |
384 function test() { | 383 function test() { |
385 assertEquals(153, tcf1()); | 384 assertEquals(153, tcf1()); |
386 assertEquals(153, tcf2()); | 385 assertEquals(153, tcf2()); |
387 assertEquals(153, tcf3()); | 386 assertEquals(153, tcf3()); |
388 assertEquals(153, tcf4()); | 387 assertEquals(153, tcf4()); |
389 } | 388 } |
390 test(); | 389 test(); |
391 test(); | 390 test(); |
392 %OptimizeFunctionOnNextCall(test); | 391 %OptimizeFunctionOnNextCall(test); |
393 test(); | 392 test(); |
394 })(); | 393 })(); |
395 | 394 |
396 | 395 |
397 // Test tail calls from arrow functions. | 396 // Test tail calls from arrow functions. |
398 (function () { | 397 (function () { |
399 function g1(a) { | 398 function g1(a) { |
400 return (() => { return f_153([f_153, test]); })(); | 399 return continue (() => { return continue f_153([f_153, test]); })(); |
401 } | 400 } |
402 | 401 |
403 function g2(a) { | 402 function g2(a) { |
404 return (() => f_153([f_153, test]))(); | 403 return continue (() => continue f_153([f_153, test]))(); |
| 404 } |
| 405 |
| 406 function g3(a) { |
| 407 var closure = () => continue f([f, closure, test], true) |
| 408 ? f_153([f_153, test]) |
| 409 : f_153([f_153, test]); |
| 410 |
| 411 return continue closure(); |
405 } | 412 } |
406 | 413 |
407 function test() { | 414 function test() { |
408 assertEquals(153, g1()); | 415 assertEquals(153, g1()); |
409 assertEquals(153, g2()); | 416 assertEquals(153, g2()); |
| 417 assertEquals(153, g3()); |
410 } | 418 } |
411 test(); | 419 test(); |
412 test(); | 420 test(); |
413 %OptimizeFunctionOnNextCall(test); | 421 %OptimizeFunctionOnNextCall(test); |
414 test(); | 422 test(); |
415 })(); | 423 })(); |
OLD | NEW |