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