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 --no-turbo-inlining | 5 // Flags: --allow-natives-syntax --harmony-tailcalls --no-turbo-inlining |
| 6 // TODO(v8:4698), TODO(ishell): support these cases. |
| 7 // Flags: --no-turbo --nostress-opt |
6 | 8 |
7 | 9 |
8 Error.prepareStackTrace = (error,stack) => { | 10 Error.prepareStackTrace = (error,stack) => { |
9 error.strace = stack; | 11 error.strace = stack; |
10 return error.message + "\n at " + stack.join("\n at "); | 12 return error.message + "\n at " + stack.join("\n at "); |
11 } | 13 } |
12 | 14 |
13 | 15 |
14 function CheckStackTrace(expected) { | 16 function checkStackTrace(expected) { |
15 var e = new Error(); | 17 var e = new Error(); |
16 e.stack; // prepare stack trace | 18 e.stack; // prepare stack trace |
17 var stack = e.strace; | 19 var stack = e.strace; |
18 assertEquals("CheckStackTrace", stack[0].getFunctionName()); | 20 assertEquals("checkStackTrace", stack[0].getFunctionName()); |
19 for (var i = 0; i < expected.length; i++) { | 21 for (var i = 0; i < expected.length; i++) { |
20 assertEquals(expected[i].name, stack[i + 1].getFunctionName()); | 22 assertEquals(expected[i].name, stack[i + 1].getFunctionName()); |
21 } | 23 } |
22 } | 24 } |
23 %NeverOptimizeFunction(CheckStackTrace); | |
24 | |
25 | |
26 function CheckArguments(expected, args) { | |
27 args = Array.prototype.slice.call(args); | |
28 assertEquals(expected, args); | |
29 } | |
30 %NeverOptimizeFunction(CheckArguments); | |
31 | 25 |
32 | 26 |
33 var CAN_INLINE_COMMENT = "// Let it be inlined."; | 27 var CAN_INLINE_COMMENT = "// Let it be inlined."; |
34 var DONT_INLINE_COMMENT = (function() { | 28 var DONT_INLINE_COMMENT = (function() { |
35 var line = "// Don't inline. Don't inline. Don't inline. Don't inline."; | 29 var line = "// Don't inline. Don't inline. Don't inline. Don't inline."; |
36 for (var i = 0; i < 4; i++) { | 30 for (var i = 0; i < 4; i++) { |
37 line += "\n " + line; | 31 line += "\n " + line; |
38 } | 32 } |
39 return line; | 33 return line; |
40 })(); | 34 })(); |
41 | 35 |
42 | 36 |
43 function ident_source(source, ident) { | 37 function ident_source(source, ident) { |
44 ident = " ".repeat(ident); | 38 ident = " ".repeat(ident); |
45 return ident + source.replace(/\n/gi, "\n" + ident); | 39 return ident + source.replace(/\n/gi, "\n" + ident); |
46 } | 40 } |
47 | 41 |
48 var global = Function('return this')(); | |
49 var the_receiver = {receiver: 1}; | |
50 | 42 |
51 function run_tests() { | 43 function run_tests() { |
52 function inlinable_comment(inlinable) { | 44 function inlinable_comment(inlinable) { |
53 return inlinable ? CAN_INLINE_COMMENT : DONT_INLINE_COMMENT; | 45 return inlinable ? CAN_INLINE_COMMENT : DONT_INLINE_COMMENT; |
54 } | 46 } |
55 | 47 |
| 48 // Check arguments manually to avoid bailing out with reason "bad value |
| 49 // context for arguments value". |
| 50 function check_arguments_template(expected_name) { |
| 51 var lines = [ |
| 52 ` assertEquals_(${expected_name}.length, arguments.length);`, |
| 53 ` for (var i = 0; i < ${expected_name}.length; i++) {`, |
| 54 ` assertEquals_(${expected_name}[i], arguments[i]);`, |
| 55 ` }`, |
| 56 ]; |
| 57 return lines.join("\n"); |
| 58 } |
| 59 var check_arguments = check_arguments_template("expected_args"); |
| 60 |
56 var f_cfg_sloppy = { | 61 var f_cfg_sloppy = { |
57 func_name: 'f', | 62 func_name: 'f', |
58 source_template: function(cfg) { | 63 source_template: function(cfg) { |
59 var receiver = cfg.f_receiver != undefined ? cfg.f_receiver | 64 var receiver = cfg.f_receiver != undefined ? cfg.f_receiver |
60 : "global"; | 65 : "global"; |
| 66 var do_checks = [ |
| 67 ` assertEquals_(${receiver}, this);`, |
| 68 ` assertEquals_(undefined, new.target);`, |
| 69 check_arguments, |
| 70 ` checkStackTrace_([f, test]);`, |
| 71 ].join("\n"); |
| 72 |
61 var lines = [ | 73 var lines = [ |
62 `function f(a) {`, | 74 `function f(a) {`, |
63 ` ${inlinable_comment(cfg.f_inlinable)}`, | 75 ` ${inlinable_comment(cfg.f_inlinable)}`, |
64 ` assertEquals(${receiver}, this);`, | 76 ` var expected_args = [${cfg.f_args}];`, |
65 ` CheckArguments([${cfg.f_args}], arguments);`, | 77 do_checks, |
66 ` CheckStackTrace([f, test]);`, | |
67 ` %DeoptimizeNow();`, | 78 ` %DeoptimizeNow();`, |
68 ` CheckArguments([${cfg.f_args}], arguments);`, | 79 do_checks, |
69 ` CheckStackTrace([f, test]);`, | |
70 ` return 42;`, | 80 ` return 42;`, |
71 `}`, | 81 `}`, |
72 ]; | 82 ]; |
73 return lines.join("\n"); | 83 return lines.join("\n"); |
74 }, | 84 }, |
75 }; | 85 }; |
76 | 86 |
77 var f_cfg_strict = { | 87 var f_cfg_strict = { |
78 func_name: 'f', | 88 func_name: 'f', |
79 source_template: function(cfg) { | 89 source_template: function(cfg) { |
80 var receiver = cfg.f_receiver != undefined ? cfg.f_receiver | 90 var receiver = cfg.f_receiver != undefined ? cfg.f_receiver |
81 : "undefined"; | 91 : "undefined"; |
| 92 var do_checks = [ |
| 93 ` assertEquals_(${receiver}, this);`, |
| 94 ` assertEquals_(undefined, new.target);`, |
| 95 check_arguments, |
| 96 ` checkStackTrace_([f, test]);`, |
| 97 ].join("\n"); |
| 98 |
82 var lines = [ | 99 var lines = [ |
83 `function f(a) {`, | 100 `function f(a) {`, |
84 ` "use strict";`, | 101 ` "use strict";`, |
85 ` ${inlinable_comment(cfg.f_inlinable)}`, | 102 ` ${inlinable_comment(cfg.f_inlinable)}`, |
86 ` assertEquals(${receiver}, this);`, | 103 ` var expected_args = [${cfg.f_args}];`, |
87 ` CheckArguments([${cfg.f_args}], arguments);`, | 104 do_checks, |
88 ` CheckStackTrace([f, test]);`, | |
89 ` %DeoptimizeNow();`, | 105 ` %DeoptimizeNow();`, |
90 ` CheckArguments([${cfg.f_args}], arguments);`, | 106 do_checks, |
91 ` CheckStackTrace([f, test]);`, | |
92 ` return 42;`, | 107 ` return 42;`, |
93 `}`, | 108 `}`, |
94 ]; | 109 ]; |
95 return lines.join("\n"); | 110 return lines.join("\n"); |
96 }, | 111 }, |
97 }; | 112 }; |
98 | 113 |
99 var f_cfg_possibly_eval = { | 114 var f_cfg_possibly_eval = { |
100 func_name: 'eval', | 115 func_name: 'eval', |
101 source_template: function(cfg) { | 116 source_template: function(cfg) { |
102 var receiver = cfg.f_receiver != undefined ? cfg.f_receiver | 117 var receiver = cfg.f_receiver != undefined ? cfg.f_receiver |
103 : "global"; | 118 : "global"; |
| 119 var do_checks = [ |
| 120 ` assertEquals_(${receiver}, this);`, |
| 121 ` assertEquals_(undefined, new.target);`, |
| 122 check_arguments, |
| 123 ` checkStackTrace_([f, test]);`, |
| 124 ].join("\n"); |
| 125 |
104 var lines = [ | 126 var lines = [ |
105 `function f(a) {`, | 127 `function f(a) {`, |
106 ` ${inlinable_comment(cfg.f_inlinable)}`, | 128 ` ${inlinable_comment(cfg.f_inlinable)}`, |
107 ` assertEquals(${receiver}, this);`, | 129 ` var expected_args = [${cfg.f_args}];`, |
108 ` CheckArguments([${cfg.f_args}], arguments);`, | 130 do_checks, |
109 ` CheckStackTrace([f, test]);`, | |
110 ` %DeoptimizeNow();`, | 131 ` %DeoptimizeNow();`, |
111 ` CheckArguments([${cfg.f_args}], arguments);`, | 132 do_checks, |
112 ` CheckStackTrace([f, test]);`, | |
113 ` return 42;`, | 133 ` return 42;`, |
114 `}`, | 134 `}`, |
115 `var eval = f;`, | 135 `var eval = f;`, |
116 ]; | 136 ]; |
117 return lines.join("\n"); | 137 return lines.join("\n"); |
118 }, | 138 }, |
119 }; | 139 }; |
120 | 140 |
121 var f_cfg_bound = { | 141 var f_cfg_bound = { |
122 func_name: 'bound', | 142 func_name: 'bound', |
123 source_template: function(cfg) { | 143 source_template: function(cfg) { |
| 144 var do_checks = [ |
| 145 ` assertEquals_(receiver, this);`, |
| 146 ` assertEquals_(undefined, new.target);`, |
| 147 check_arguments, |
| 148 ` checkStackTrace_([f, test]);`, |
| 149 ].join("\n"); |
| 150 |
124 var lines = [ | 151 var lines = [ |
125 `function f(a) {`, | 152 `function f(a) {`, |
126 ` "use strict";`, | 153 ` "use strict";`, |
127 ` ${inlinable_comment(cfg.f_inlinable)}`, | 154 ` ${inlinable_comment(cfg.f_inlinable)}`, |
128 ` assertEquals(receiver, this);`, | 155 ` var expected_args = [${cfg.f_args}];`, |
129 ` CheckArguments([${cfg.f_args}], arguments);`, | 156 do_checks, |
130 ` CheckStackTrace([f, test]);`, | |
131 ` %DeoptimizeNow();`, | 157 ` %DeoptimizeNow();`, |
132 ` CheckArguments([${cfg.f_args}], arguments);`, | 158 do_checks, |
133 ` CheckStackTrace([f, test]);`, | |
134 ` return 42;`, | 159 ` return 42;`, |
135 `}`, | 160 `}`, |
136 `var receiver = {a: 153};`, | 161 `var receiver = {a: 153};`, |
137 `var bound = f.bind(receiver);`, | 162 `var bound = f.bind(receiver);`, |
138 ]; | 163 ]; |
139 return lines.join("\n"); | 164 return lines.join("\n"); |
140 }, | 165 }, |
141 }; | 166 }; |
142 | 167 |
143 var f_cfg_proxy = { | 168 var f_cfg_proxy = { |
144 func_name: 'p', | 169 func_name: 'p', |
145 source_template: function(cfg) { | 170 source_template: function(cfg) { |
146 var receiver = cfg.f_receiver != undefined ? cfg.f_receiver | 171 var receiver = cfg.f_receiver != undefined ? cfg.f_receiver |
147 : "global"; | 172 : "global"; |
| 173 var do_checks = [ |
| 174 ` assertEquals_(${receiver}, this);`, |
| 175 ` assertEquals_(undefined, new.target);`, |
| 176 check_arguments, |
| 177 ` checkStackTrace_([f, test]);`, |
| 178 ].join("\n"); |
| 179 |
148 var lines = [ | 180 var lines = [ |
149 `function f(a) {`, | 181 `function f(a) {`, |
150 ` ${inlinable_comment(cfg.f_inlinable)}`, | 182 ` ${inlinable_comment(cfg.f_inlinable)}`, |
151 ` assertEquals(${receiver}, this);`, | 183 ` var expected_args = [${cfg.f_args}];`, |
152 ` CheckArguments([${cfg.f_args}], arguments);`, | 184 do_checks, |
153 ` CheckStackTrace([f, test]);`, | |
154 ` %DeoptimizeNow();`, | 185 ` %DeoptimizeNow();`, |
155 ` CheckArguments([${cfg.f_args}], arguments);`, | 186 do_checks, |
156 ` CheckStackTrace([f, test]);`, | |
157 ` return 42;`, | 187 ` return 42;`, |
158 `}`, | 188 `}`, |
159 `var p = new Proxy(f, {});`, | 189 `var p = new Proxy(f, {});`, |
160 ]; | 190 ]; |
161 return lines.join("\n"); | 191 return lines.join("\n"); |
162 }, | 192 }, |
163 }; | 193 }; |
164 | 194 |
165 var g_cfg_normal = { | 195 var g_cfg_normal = { |
166 receiver: undefined, | 196 receiver: undefined, |
167 source_template: function(cfg) { | 197 source_template: function(cfg) { |
168 var lines = [ | 198 var lines = [ |
169 `function g(a) {`, | 199 `function g(a) {`, |
170 ` "use strict";`, | 200 ` "use strict";`, |
171 ` ${inlinable_comment(cfg.g_inlinable)}`, | 201 ` ${inlinable_comment(cfg.g_inlinable)}`, |
172 ` CheckArguments([${cfg.g_args}], arguments);`, | 202 ` var expected_args = [${cfg.g_args}];`, |
| 203 check_arguments, |
173 ` return ${cfg.f_name}(${cfg.f_args});`, | 204 ` return ${cfg.f_name}(${cfg.f_args});`, |
174 `}`, | 205 `}`, |
175 ]; | 206 ]; |
176 return lines.join("\n"); | 207 return lines.join("\n"); |
177 }, | 208 }, |
178 }; | 209 }; |
179 | 210 |
180 | 211 |
181 var g_cfg_function_apply = { | 212 var g_cfg_function_apply = { |
182 receiver: "the_receiver", | 213 receiver: "the_receiver", |
183 source_template: function(cfg) { | 214 source_template: function(cfg) { |
184 var lines = [ | 215 var lines = [ |
185 `function g(a) {`, | 216 `function g(a) {`, |
186 ` "use strict";`, | 217 ` "use strict";`, |
187 ` ${inlinable_comment(cfg.g_inlinable)}`, | 218 ` ${inlinable_comment(cfg.g_inlinable)}`, |
188 ` CheckArguments([${cfg.g_args}], arguments);`, | 219 ` var expected_args = [${cfg.g_args}];`, |
| 220 check_arguments, |
189 ` return ${cfg.f_name}.apply(the_receiver, [${cfg.f_args}]);`, | 221 ` return ${cfg.f_name}.apply(the_receiver, [${cfg.f_args}]);`, |
190 `}`, | 222 `}`, |
191 ]; | 223 ]; |
192 return lines.join("\n"); | 224 return lines.join("\n"); |
193 }, | 225 }, |
194 }; | 226 }; |
195 | 227 |
196 | 228 |
| 229 var g_cfg_function_apply_arguments_object = { |
| 230 receiver: "the_receiver", |
| 231 source_template: function(cfg) { |
| 232 cfg.f_args = cfg.g_args; |
| 233 var lines = [ |
| 234 `function g(a) {`, |
| 235 ` "use strict";`, |
| 236 ` ${inlinable_comment(cfg.g_inlinable)}`, |
| 237 ` var expected_args = [${cfg.g_args}];`, |
| 238 check_arguments, |
| 239 ` return ${cfg.f_name}.apply(the_receiver, arguments);`, |
| 240 `}`, |
| 241 ]; |
| 242 return lines.join("\n"); |
| 243 }, |
| 244 }; |
| 245 |
| 246 |
197 var g_cfg_function_call = { | 247 var g_cfg_function_call = { |
198 receiver: "the_receiver", | 248 receiver: "the_receiver", |
199 source_template: function(cfg) { | 249 source_template: function(cfg) { |
200 var f_args = "the_receiver"; | 250 var f_args = "the_receiver"; |
201 if (cfg.f_args !== "") f_args += ", "; | 251 if (cfg.f_args !== "") f_args += ", "; |
202 f_args += cfg.f_args; | 252 f_args += cfg.f_args; |
203 | 253 |
204 var lines = [ | 254 var lines = [ |
205 `function g(a) {`, | 255 `function g(a) {`, |
206 ` "use strict";`, | 256 ` "use strict";`, |
207 ` ${inlinable_comment(cfg.g_inlinable)}`, | 257 ` ${inlinable_comment(cfg.g_inlinable)}`, |
208 ` CheckArguments([${cfg.g_args}], arguments);`, | 258 ` var expected_args = [${cfg.g_args}];`, |
| 259 check_arguments, |
209 ` return ${cfg.f_name}.call(${f_args});`, | 260 ` return ${cfg.f_name}.call(${f_args});`, |
210 `}`, | 261 `}`, |
211 ]; | 262 ]; |
212 return lines.join("\n"); | 263 return lines.join("\n"); |
213 }, | 264 }, |
214 }; | 265 }; |
215 | 266 |
216 | 267 |
217 function test_template(cfg) { | 268 function test_template(cfg) { |
| 269 // Note: g_source_template modifies cfg.f_args in some cases. |
| 270 var g_source = cfg.g_source_template(cfg); |
| 271 g_source = ident_source(g_source, 2); |
| 272 |
218 var f_source = cfg.f_source_template(cfg); | 273 var f_source = cfg.f_source_template(cfg); |
219 var g_source = cfg.g_source_template(cfg); | |
220 f_source = ident_source(f_source, 2); | 274 f_source = ident_source(f_source, 2); |
221 g_source = ident_source(g_source, 2); | |
222 | 275 |
223 var lines = [ | 276 var lines = [ |
224 `(function() {`, | 277 `(function() {`, |
| 278 ` // Avoid bailing out because of "Reference to a variable which requires
dynamic lookup".`, |
| 279 ` var assertEquals_ = assertEquals;`, |
| 280 ` var checkStackTrace_ = checkStackTrace;`, |
| 281 ` var undefined = void 0;`, |
| 282 ` var global = Function('return this')();`, |
| 283 ` var the_receiver = {receiver: 1};`, |
| 284 ``, |
| 285 ` // Don't inline helper functions`, |
| 286 ` %NeverOptimizeFunction(assertEquals);`, |
| 287 ` %NeverOptimizeFunction(checkStackTrace);`, |
| 288 ``, |
225 f_source, | 289 f_source, |
226 g_source, | 290 g_source, |
227 ` function test() {`, | 291 ` function test() {`, |
228 ` "use strict";`, | 292 ` "use strict";`, |
229 ` assertEquals(42, g(${cfg.g_args}));`, | 293 ` assertEquals_(42, g(${cfg.g_args}));`, |
230 ` }`, | 294 ` }`, |
231 ` ${cfg.f_inlinable ? "%SetForceInlineFlag(f)" : ""};`, | 295 ` ${cfg.f_inlinable ? "%SetForceInlineFlag(f)" : ""};`, |
232 ` ${cfg.g_inlinable ? "%SetForceInlineFlag(g)" : ""};`, | 296 ` ${cfg.g_inlinable ? "%SetForceInlineFlag(g)" : ""};`, |
233 ``, | 297 ` ${"test();".repeat(cfg.test_warmup_count)}`, |
234 ` test();`, | |
235 ` %OptimizeFunctionOnNextCall(test);`, | 298 ` %OptimizeFunctionOnNextCall(test);`, |
236 ` %OptimizeFunctionOnNextCall(f);`, | 299 ` %OptimizeFunctionOnNextCall(f);`, |
237 ` %OptimizeFunctionOnNextCall(g);`, | 300 ` %OptimizeFunctionOnNextCall(g);`, |
238 ` test();`, | 301 ` test();`, |
239 `})();`, | 302 `})();`, |
240 ``, | 303 ``, |
241 ]; | 304 ]; |
242 var source = lines.join("\n"); | 305 var source = lines.join("\n"); |
243 return source; | 306 return source; |
244 } | 307 } |
245 | 308 |
246 // TODO(v8:4698), TODO(ishell): support all commented cases. | 309 // TODO(v8:4698), TODO(ishell): support all commented cases. |
247 var f_args_variants = ["", "1", "1, 2"]; | 310 var f_args_variants = ["", "1", "1, 2"]; |
248 var g_args_variants = [/*"",*/ "10", /*"10, 20"*/]; | 311 var g_args_variants = ["", "10", "10, 20"]; |
249 var f_inlinable_variants = [/*true,*/ false]; | 312 var f_inlinable_variants = [/*true,*/ false]; |
250 var g_inlinable_variants = [true, false]; | 313 var g_inlinable_variants = [/*true,*/ false]; |
251 var f_variants = [ | 314 var f_variants = [ |
252 f_cfg_sloppy, | 315 f_cfg_sloppy, |
253 f_cfg_strict, | 316 f_cfg_strict, |
254 f_cfg_bound, | 317 f_cfg_bound, |
255 f_cfg_proxy, | 318 f_cfg_proxy, |
256 f_cfg_possibly_eval, | 319 f_cfg_possibly_eval, |
257 ]; | 320 ]; |
258 var g_variants = [ | 321 var g_variants = [ |
259 g_cfg_normal, | 322 g_cfg_normal, |
260 g_cfg_function_call, | 323 g_cfg_function_call, |
261 g_cfg_function_apply, | 324 g_cfg_function_apply, |
| 325 g_cfg_function_apply_arguments_object, |
262 ]; | 326 ]; |
| 327 var test_warmup_counts = [0, 1, 2]; |
263 | 328 |
264 f_variants.forEach((f_cfg) => { | 329 f_variants.forEach((f_cfg) => { |
265 g_variants.forEach((g_cfg) => { | 330 g_variants.forEach((g_cfg) => { |
266 f_args_variants.forEach((f_args) => { | 331 f_args_variants.forEach((f_args) => { |
267 g_args_variants.forEach((g_args) => { | 332 g_args_variants.forEach((g_args) => { |
268 f_inlinable_variants.forEach((f_inlinable) => { | 333 f_inlinable_variants.forEach((f_inlinable) => { |
269 g_inlinable_variants.forEach((g_inlinable) => { | 334 g_inlinable_variants.forEach((g_inlinable) => { |
270 var cfg = { | 335 test_warmup_counts.forEach((test_warmup_count) => { |
271 f_source_template: f_cfg.source_template, | 336 var cfg = { |
272 f_inlinable, | 337 f_source_template: f_cfg.source_template, |
273 f_args, | 338 f_inlinable, |
274 f_name: f_cfg.func_name, | 339 f_args, |
275 f_receiver: g_cfg.receiver, | 340 f_name: f_cfg.func_name, |
276 g_source_template: g_cfg.source_template, | 341 f_receiver: g_cfg.receiver, |
277 g_inlinable, | 342 g_source_template: g_cfg.source_template, |
278 g_args, | 343 g_inlinable, |
279 }; | 344 g_args, |
280 var source = test_template(cfg); | 345 test_warmup_count, |
281 print("===================="); | 346 }; |
282 print(source); | 347 var source = test_template(cfg); |
283 eval(source); | 348 print("===================="); |
| 349 print(source); |
| 350 eval(source); |
| 351 }); |
284 }); | 352 }); |
285 }); | 353 }); |
286 }); | 354 }); |
287 }); | 355 }); |
288 }); | 356 }); |
289 }); | 357 }); |
290 } | 358 } |
291 | 359 |
292 run_tests(); | 360 run_tests(); |
OLD | NEW |