Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame^] | 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-tailcalls --no-turbo-inlining |
| 6 | |
| 7 | |
| 8 | Error.prepareStackTrace = (error,stack) => { |
| 9 | error.strace = stack; |
| 10 | return error.message + "\n at " + stack.join("\n at "); |
| 11 | } |
| 12 | |
| 13 | |
| 14 | function CheckStackTrace(expected) { |
| 15 | var e = new Error(); |
| 16 | e.stack; // prepare stack trace |
| 17 | var stack = e.strace; |
| 18 | assertEquals("CheckStackTrace", stack[0].getFunctionName()); |
| 19 | for (var i = 0; i < expected.length; i++) { |
| 20 | assertEquals(expected[i].name, stack[i + 1].getFunctionName()); |
| 21 | } |
| 22 | } |
| 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 | |
| 32 | |
| 33 | var CAN_INLINE_COMMENT = "// Let it be inlined."; |
| 34 | var DONT_INLINE_COMMENT = (function() { |
| 35 | var line = "// Don't inline. Don't inline. Don't inline. Don't inline."; |
| 36 | for (var i = 0; i < 4; i++) { |
| 37 | line += "\n " + line; |
| 38 | } |
| 39 | return line; |
| 40 | })(); |
| 41 | |
| 42 | |
| 43 | function ident_source(source, ident) { |
| 44 | ident = " ".repeat(ident); |
| 45 | return ident + source.replace(/\n/gi, "\n" + ident); |
| 46 | } |
| 47 | |
| 48 | var global = Function('return this')(); |
| 49 | var the_receiver = {receiver: 1}; |
| 50 | |
| 51 | function run_tests() { |
| 52 | function inlinable_comment(inlinable) { |
| 53 | return inlinable ? CAN_INLINE_COMMENT : DONT_INLINE_COMMENT; |
| 54 | } |
| 55 | |
| 56 | var f_cfg_sloppy = { |
| 57 | func_name: 'f', |
| 58 | source_template: function(cfg) { |
| 59 | var receiver = cfg.f_receiver != undefined ? cfg.f_receiver |
| 60 | : "global"; |
| 61 | var lines = [ |
| 62 | `function f(a) {`, |
| 63 | ` ${inlinable_comment(cfg.f_inlinable)}`, |
| 64 | ` assertEquals(${receiver}, this);`, |
| 65 | ` CheckArguments([${cfg.f_args}], arguments);`, |
| 66 | ` CheckStackTrace([f, test]);`, |
| 67 | ` %DeoptimizeNow();`, |
| 68 | ` CheckArguments([${cfg.f_args}], arguments);`, |
| 69 | ` CheckStackTrace([f, test]);`, |
| 70 | ` return 42;`, |
| 71 | `}`, |
| 72 | ]; |
| 73 | return lines.join("\n"); |
| 74 | }, |
| 75 | }; |
| 76 | |
| 77 | var f_cfg_strict = { |
| 78 | func_name: 'f', |
| 79 | source_template: function(cfg) { |
| 80 | var receiver = cfg.f_receiver != undefined ? cfg.f_receiver |
| 81 | : "undefined"; |
| 82 | var lines = [ |
| 83 | `function f(a) {`, |
| 84 | ` "use strict";`, |
| 85 | ` ${inlinable_comment(cfg.f_inlinable)}`, |
| 86 | ` assertEquals(${receiver}, this);`, |
| 87 | ` CheckArguments([${cfg.f_args}], arguments);`, |
| 88 | ` CheckStackTrace([f, test]);`, |
| 89 | ` %DeoptimizeNow();`, |
| 90 | ` CheckArguments([${cfg.f_args}], arguments);`, |
| 91 | ` CheckStackTrace([f, test]);`, |
| 92 | ` return 42;`, |
| 93 | `}`, |
| 94 | ]; |
| 95 | return lines.join("\n"); |
| 96 | }, |
| 97 | }; |
| 98 | |
| 99 | var f_cfg_possibly_eval = { |
| 100 | func_name: 'eval', |
| 101 | source_template: function(cfg) { |
| 102 | var receiver = cfg.f_receiver != undefined ? cfg.f_receiver |
| 103 | : "global"; |
| 104 | var lines = [ |
| 105 | `function f(a) {`, |
| 106 | ` ${inlinable_comment(cfg.f_inlinable)}`, |
| 107 | ` assertEquals(${receiver}, this);`, |
| 108 | ` CheckArguments([${cfg.f_args}], arguments);`, |
| 109 | ` CheckStackTrace([f, test]);`, |
| 110 | ` %DeoptimizeNow();`, |
| 111 | ` CheckArguments([${cfg.f_args}], arguments);`, |
| 112 | ` CheckStackTrace([f, test]);`, |
| 113 | ` return 42;`, |
| 114 | `}`, |
| 115 | `var eval = f;`, |
| 116 | ]; |
| 117 | return lines.join("\n"); |
| 118 | }, |
| 119 | }; |
| 120 | |
| 121 | var f_cfg_bound = { |
| 122 | func_name: 'bound', |
| 123 | source_template: function(cfg) { |
| 124 | var lines = [ |
| 125 | `function f(a) {`, |
| 126 | ` "use strict";`, |
| 127 | ` ${inlinable_comment(cfg.f_inlinable)}`, |
| 128 | ` assertEquals(receiver, this);`, |
| 129 | ` CheckArguments([${cfg.f_args}], arguments);`, |
| 130 | ` CheckStackTrace([f, test]);`, |
| 131 | ` %DeoptimizeNow();`, |
| 132 | ` CheckArguments([${cfg.f_args}], arguments);`, |
| 133 | ` CheckStackTrace([f, test]);`, |
| 134 | ` return 42;`, |
| 135 | `}`, |
| 136 | `var receiver = {a: 153};`, |
| 137 | `var bound = f.bind(receiver);`, |
| 138 | ]; |
| 139 | return lines.join("\n"); |
| 140 | }, |
| 141 | }; |
| 142 | |
| 143 | var f_cfg_proxy = { |
| 144 | func_name: 'p', |
| 145 | source_template: function(cfg) { |
| 146 | var receiver = cfg.f_receiver != undefined ? cfg.f_receiver |
| 147 | : "global"; |
| 148 | var lines = [ |
| 149 | `function f(a) {`, |
| 150 | ` ${inlinable_comment(cfg.f_inlinable)}`, |
| 151 | ` assertEquals(${receiver}, this);`, |
| 152 | ` CheckArguments([${cfg.f_args}], arguments);`, |
| 153 | ` CheckStackTrace([f, test]);`, |
| 154 | ` %DeoptimizeNow();`, |
| 155 | ` CheckArguments([${cfg.f_args}], arguments);`, |
| 156 | ` CheckStackTrace([f, test]);`, |
| 157 | ` return 42;`, |
| 158 | `}`, |
| 159 | `var p = new Proxy(f, {});`, |
| 160 | ]; |
| 161 | return lines.join("\n"); |
| 162 | }, |
| 163 | }; |
| 164 | |
| 165 | var g_cfg_normal = { |
| 166 | receiver: undefined, |
| 167 | source_template: function(cfg) { |
| 168 | var lines = [ |
| 169 | `function g(a) {`, |
| 170 | ` "use strict";`, |
| 171 | ` ${inlinable_comment(cfg.g_inlinable)}`, |
| 172 | ` CheckArguments([${cfg.g_args}], arguments);`, |
| 173 | ` return ${cfg.f_name}(${cfg.f_args});`, |
| 174 | `}`, |
| 175 | ]; |
| 176 | return lines.join("\n"); |
| 177 | }, |
| 178 | }; |
| 179 | |
| 180 | |
| 181 | var g_cfg_function_apply = { |
| 182 | receiver: "the_receiver", |
| 183 | source_template: function(cfg) { |
| 184 | var lines = [ |
| 185 | `function g(a) {`, |
| 186 | ` "use strict";`, |
| 187 | ` ${inlinable_comment(cfg.g_inlinable)}`, |
| 188 | ` CheckArguments([${cfg.g_args}], arguments);`, |
| 189 | ` return ${cfg.f_name}.apply(the_receiver, [${cfg.f_args}]);`, |
| 190 | `}`, |
| 191 | ]; |
| 192 | return lines.join("\n"); |
| 193 | }, |
| 194 | }; |
| 195 | |
| 196 | |
| 197 | var g_cfg_function_call = { |
| 198 | receiver: "the_receiver", |
| 199 | source_template: function(cfg) { |
| 200 | var f_args = "the_receiver"; |
| 201 | if (cfg.f_args !== "") f_args += ", "; |
| 202 | f_args += cfg.f_args; |
| 203 | |
| 204 | var lines = [ |
| 205 | `function g(a) {`, |
| 206 | ` "use strict";`, |
| 207 | ` ${inlinable_comment(cfg.g_inlinable)}`, |
| 208 | ` CheckArguments([${cfg.g_args}], arguments);`, |
| 209 | ` return ${cfg.f_name}.call(${f_args});`, |
| 210 | `}`, |
| 211 | ]; |
| 212 | return lines.join("\n"); |
| 213 | }, |
| 214 | }; |
| 215 | |
| 216 | |
| 217 | function test_template(cfg) { |
| 218 | 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); |
| 221 | g_source = ident_source(g_source, 2); |
| 222 | |
| 223 | var lines = [ |
| 224 | `(function() {`, |
| 225 | f_source, |
| 226 | g_source, |
| 227 | ` function test() {`, |
| 228 | ` "use strict";`, |
| 229 | ` assertEquals(42, g(${cfg.g_args}));`, |
| 230 | ` }`, |
| 231 | ` ${cfg.f_inlinable ? "%SetForceInlineFlag(f)" : ""};`, |
| 232 | ` ${cfg.g_inlinable ? "%SetForceInlineFlag(g)" : ""};`, |
| 233 | ``, |
| 234 | ` test();`, |
| 235 | ` %OptimizeFunctionOnNextCall(test);`, |
| 236 | ` %OptimizeFunctionOnNextCall(f);`, |
| 237 | ` %OptimizeFunctionOnNextCall(g);`, |
| 238 | ` test();`, |
| 239 | `})();`, |
| 240 | ``, |
| 241 | ]; |
| 242 | var source = lines.join("\n"); |
| 243 | return source; |
| 244 | } |
| 245 | |
| 246 | // TODO(v8:4698), TODO(ishell): support all commented cases. |
| 247 | var f_args_variants = ["", "1", "1, 2"]; |
| 248 | var g_args_variants = [/*"",*/ "10", /*"10, 20"*/]; |
| 249 | var f_inlinable_variants = [/*true,*/ false]; |
| 250 | var g_inlinable_variants = [true, false]; |
| 251 | var f_variants = [ |
| 252 | f_cfg_sloppy, |
| 253 | f_cfg_strict, |
| 254 | f_cfg_bound, |
| 255 | f_cfg_proxy, |
| 256 | f_cfg_possibly_eval, |
| 257 | ]; |
| 258 | var g_variants = [ |
| 259 | g_cfg_normal, |
| 260 | g_cfg_function_call, |
| 261 | g_cfg_function_apply, |
| 262 | ]; |
| 263 | |
| 264 | f_variants.forEach((f_cfg) => { |
| 265 | g_variants.forEach((g_cfg) => { |
| 266 | f_args_variants.forEach((f_args) => { |
| 267 | g_args_variants.forEach((g_args) => { |
| 268 | f_inlinable_variants.forEach((f_inlinable) => { |
| 269 | g_inlinable_variants.forEach((g_inlinable) => { |
| 270 | var cfg = { |
| 271 | f_source_template: f_cfg.source_template, |
| 272 | f_inlinable, |
| 273 | f_args, |
| 274 | f_name: f_cfg.func_name, |
| 275 | f_receiver: g_cfg.receiver, |
| 276 | g_source_template: g_cfg.source_template, |
| 277 | g_inlinable, |
| 278 | g_args, |
| 279 | }; |
| 280 | var source = test_template(cfg); |
| 281 | print("===================="); |
| 282 | print(source); |
| 283 | eval(source); |
| 284 | }); |
| 285 | }); |
| 286 | }); |
| 287 | }); |
| 288 | }); |
| 289 | }); |
| 290 | } |
| 291 | |
| 292 | run_tests(); |