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