1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 29 #include "src/v8.h" 30 31 #include "src/api.h" 32 #include "src/debug/debug.h" 33 #include "src/string-search.h" 34 #include "test/cctest/cctest.h" 35 36 37 using ::v8::base::SmartArrayPointer; 38 using ::v8::internal::CStrVector; 39 using ::v8::internal::Factory; 40 using ::v8::internal::Handle; 41 using ::v8::internal::Heap; 42 using ::v8::internal::Isolate; 43 using ::v8::internal::JSFunction; 44 using ::v8::internal::Object; 45 using ::v8::internal::Runtime; 46 using ::v8::internal::Script; 47 using ::v8::internal::SharedFunctionInfo; 48 using ::v8::internal::String; 49 using ::v8::internal::Vector; 50 51 52 static void CheckFunctionName(v8::Local<v8::Script> script, 53 const char* func_pos_src, 54 const char* ref_inferred_name) { 55 Isolate* isolate = CcTest::i_isolate(); 56 57 // Get script source. 58 Handle<Object> obj = v8::Utils::OpenHandle(*script); 59 Handle<SharedFunctionInfo> shared_function; 60 if (obj->IsSharedFunctionInfo()) { 61 shared_function = 62 Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(*obj)); 63 } else { 64 shared_function = 65 Handle<SharedFunctionInfo>(JSFunction::cast(*obj)->shared()); 66 } 67 Handle<Script> i_script(Script::cast(shared_function->script())); 68 CHECK(i_script->source()->IsString()); 69 Handle<String> script_src(String::cast(i_script->source())); 70 71 // Find the position of a given func source substring in the source. 72 int func_pos; 73 { 74 i::DisallowHeapAllocation no_gc; 75 Vector<const uint8_t> func_pos_str = i::OneByteVector(func_pos_src); 76 String::FlatContent script_content = script_src->GetFlatContent(); 77 func_pos = SearchString(isolate, script_content.ToOneByteVector(), 78 func_pos_str, 0); 79 } 80 CHECK_NE(0, func_pos); 81 82 // Obtain SharedFunctionInfo for the function. 83 Handle<SharedFunctionInfo> shared_func_info = 84 Handle<SharedFunctionInfo>::cast( 85 isolate->debug()->FindSharedFunctionInfoInScript(i_script, func_pos)); 86 87 // Verify inferred function name. 88 SmartArrayPointer<char> inferred_name = 89 shared_func_info->inferred_name()->ToCString(); 90 i::PrintF("expected: %s, found: %s\n", ref_inferred_name, 91 inferred_name.get()); 92 CHECK_EQ(0, strcmp(ref_inferred_name, inferred_name.get())); 93 } 94 95 96 static v8::Local<v8::Script> Compile(v8::Isolate* isolate, const char* src) { 97 return v8::Script::Compile( 98 isolate->GetCurrentContext(), 99 v8::String::NewFromUtf8(isolate, src, v8::NewStringType::kNormal) 100 .ToLocalChecked()) 101 .ToLocalChecked(); 102 } 103 104 105 TEST(GlobalProperty) { 106 CcTest::InitializeVM(); 107 v8::HandleScope scope(CcTest::isolate()); 108 109 v8::Local<v8::Script> script = Compile(CcTest::isolate(), 110 "fun1 = function() { return 1; }\n" 111 "fun2 = function() { return 2; }\n"); 112 CheckFunctionName(script, "return 1", "fun1"); 113 CheckFunctionName(script, "return 2", "fun2"); 114 } 115 116 117 TEST(GlobalVar) { 118 CcTest::InitializeVM(); 119 v8::HandleScope scope(CcTest::isolate()); 120 121 v8::Local<v8::Script> script = 122 Compile(CcTest::isolate(), 123 "var fun1 = function() { return 1; }\n" 124 "var fun2 = function() { return 2; }\n"); 125 CheckFunctionName(script, "return 1", "fun1"); 126 CheckFunctionName(script, "return 2", "fun2"); 127 } 128 129 130 TEST(LocalVar) { 131 CcTest::InitializeVM(); 132 v8::HandleScope scope(CcTest::isolate()); 133 134 v8::Local<v8::Script> script = 135 Compile(CcTest::isolate(), 136 "function outer() {\n" 137 " var fun1 = function() { return 1; }\n" 138 " var fun2 = function() { return 2; }\n" 139 "}"); 140 CheckFunctionName(script, "return 1", "fun1"); 141 CheckFunctionName(script, "return 2", "fun2"); 142 } 143 144 145 TEST(InConstructor) { 146 CcTest::InitializeVM(); 147 v8::HandleScope scope(CcTest::isolate()); 148 149 v8::Local<v8::Script> script = 150 Compile(CcTest::isolate(), 151 "function MyClass() {\n" 152 " this.method1 = function() { return 1; }\n" 153 " this.method2 = function() { return 2; }\n" 154 "}"); 155 CheckFunctionName(script, "return 1", "MyClass.method1"); 156 CheckFunctionName(script, "return 2", "MyClass.method2"); 157 } 158 159 160 TEST(Factory) { 161 CcTest::InitializeVM(); 162 v8::HandleScope scope(CcTest::isolate()); 163 164 v8::Local<v8::Script> script = 165 Compile(CcTest::isolate(), 166 "function createMyObj() {\n" 167 " var obj = {};\n" 168 " obj.method1 = function() { return 1; }\n" 169 " obj.method2 = function() { return 2; }\n" 170 " return obj;\n" 171 "}"); 172 CheckFunctionName(script, "return 1", "obj.method1"); 173 CheckFunctionName(script, "return 2", "obj.method2"); 174 } 175 176 177 TEST(Static) { 178 CcTest::InitializeVM(); 179 v8::HandleScope scope(CcTest::isolate()); 180 181 v8::Local<v8::Script> script = 182 Compile(CcTest::isolate(), 183 "function MyClass() {}\n" 184 "MyClass.static1 = function() { return 1; }\n" 185 "MyClass.static2 = function() { return 2; }\n" 186 "MyClass.MyInnerClass = {}\n" 187 "MyClass.MyInnerClass.static3 = function() { return 3; }\n" 188 "MyClass.MyInnerClass.static4 = function() { return 4; }"); 189 CheckFunctionName(script, "return 1", "MyClass.static1"); 190 CheckFunctionName(script, "return 2", "MyClass.static2"); 191 CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.static3"); 192 CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.static4"); 193 } 194 195 196 TEST(Prototype) { 197 CcTest::InitializeVM(); 198 v8::HandleScope scope(CcTest::isolate()); 199 200 v8::Local<v8::Script> script = Compile( 201 CcTest::isolate(), 202 "function MyClass() {}\n" 203 "MyClass.prototype.method1 = function() { return 1; }\n" 204 "MyClass.prototype.method2 = function() { return 2; }\n" 205 "MyClass.MyInnerClass = function() {}\n" 206 "MyClass.MyInnerClass.prototype.method3 = function() { return 3; }\n" 207 "MyClass.MyInnerClass.prototype.method4 = function() { return 4; }"); 208 CheckFunctionName(script, "return 1", "MyClass.method1"); 209 CheckFunctionName(script, "return 2", "MyClass.method2"); 210 CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.method3"); 211 CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.method4"); 212 } 213 214 215 TEST(ObjectLiteral) { 216 CcTest::InitializeVM(); 217 v8::HandleScope scope(CcTest::isolate()); 218 219 v8::Local<v8::Script> script = 220 Compile(CcTest::isolate(), 221 "function MyClass() {}\n" 222 "MyClass.prototype = {\n" 223 " method1: function() { return 1; },\n" 224 " method2: function() { return 2; } }"); 225 CheckFunctionName(script, "return 1", "MyClass.method1"); 226 CheckFunctionName(script, "return 2", "MyClass.method2"); 227 } 228 229 230 TEST(UpperCaseClass) { 231 CcTest::InitializeVM(); 232 v8::HandleScope scope(CcTest::isolate()); 233 234 v8::Local<v8::Script> script = Compile(CcTest::isolate(), 235 "'use strict';\n" 236 "class MyClass {\n" 237 " constructor() {\n" 238 " this.value = 1;\n" 239 " }\n" 240 " method() {\n" 241 " this.value = 2;\n" 242 " }\n" 243 "}"); 244 CheckFunctionName(script, "this.value = 1", "MyClass"); 245 CheckFunctionName(script, "this.value = 2", "MyClass.method"); 246 } 247 248 249 TEST(LowerCaseClass) { 250 CcTest::InitializeVM(); 251 v8::HandleScope scope(CcTest::isolate()); 252 253 v8::Local<v8::Script> script = Compile(CcTest::isolate(), 254 "'use strict';\n" 255 "class myclass {\n" 256 " constructor() {\n" 257 " this.value = 1;\n" 258 " }\n" 259 " method() {\n" 260 " this.value = 2;\n" 261 " }\n" 262 "}"); 263 CheckFunctionName(script, "this.value = 1", "myclass"); 264 CheckFunctionName(script, "this.value = 2", "myclass.method"); 265 } 266 267 268 TEST(AsParameter) { 269 CcTest::InitializeVM(); 270 v8::HandleScope scope(CcTest::isolate()); 271 272 v8::Local<v8::Script> script = Compile( 273 CcTest::isolate(), 274 "function f1(a) { return a(); }\n" 275 "function f2(a, b) { return a() + b(); }\n" 276 "var result1 = f1(function() { return 1; })\n" 277 "var result2 = f2(function() { return 2; }, function() { return 3; })"); 278 // Can't infer names here. 279 CheckFunctionName(script, "return 1", ""); 280 CheckFunctionName(script, "return 2", ""); 281 CheckFunctionName(script, "return 3", ""); 282 } 283 284 285 TEST(MultipleFuncsConditional) { 286 CcTest::InitializeVM(); 287 v8::HandleScope scope(CcTest::isolate()); 288 289 v8::Local<v8::Script> script = Compile(CcTest::isolate(), 290 "fun1 = 0 ?\n" 291 " function() { return 1; } :\n" 292 " function() { return 2; }"); 293 CheckFunctionName(script, "return 1", "fun1"); 294 CheckFunctionName(script, "return 2", "fun1"); 295 } 296 297 298 TEST(MultipleFuncsInLiteral) { 299 CcTest::InitializeVM(); 300 v8::HandleScope scope(CcTest::isolate()); 301 302 v8::Local<v8::Script> script = 303 Compile(CcTest::isolate(), 304 "function MyClass() {}\n" 305 "MyClass.prototype = {\n" 306 " method1: 0 ? function() { return 1; } :\n" 307 " function() { return 2; } }"); 308 CheckFunctionName(script, "return 1", "MyClass.method1"); 309 CheckFunctionName(script, "return 2", "MyClass.method1"); 310 } 311 312 313 TEST(AnonymousInAnonymousClosure1) { 314 CcTest::InitializeVM(); 315 v8::HandleScope scope(CcTest::isolate()); 316 317 v8::Local<v8::Script> script = Compile(CcTest::isolate(), 318 "(function() {\n" 319 " (function() {\n" 320 " var a = 1;\n" 321 " return;\n" 322 " })();\n" 323 " var b = function() {\n" 324 " var c = 1;\n" 325 " return;\n" 326 " };\n" 327 "})();"); 328 CheckFunctionName(script, "return", ""); 329 } 330 331 332 TEST(AnonymousInAnonymousClosure2) { 333 CcTest::InitializeVM(); 334 v8::HandleScope scope(CcTest::isolate()); 335 336 v8::Local<v8::Script> script = Compile(CcTest::isolate(), 337 "(function() {\n" 338 " (function() {\n" 339 " var a = 1;\n" 340 " return;\n" 341 " })();\n" 342 " var c = 1;\n" 343 "})();"); 344 CheckFunctionName(script, "return", ""); 345 } 346 347 348 TEST(NamedInAnonymousClosure) { 349 CcTest::InitializeVM(); 350 v8::HandleScope scope(CcTest::isolate()); 351 352 v8::Local<v8::Script> script = Compile(CcTest::isolate(), 353 "var foo = function() {\n" 354 " (function named() {\n" 355 " var a = 1;\n" 356 " })();\n" 357 " var c = 1;\n" 358 " return;\n" 359 "};"); 360 CheckFunctionName(script, "return", "foo"); 361 } 362 363 364 // See http://code.google.com/p/v8/issues/detail?id=380 365 TEST(Issue380) { 366 CcTest::InitializeVM(); 367 v8::HandleScope scope(CcTest::isolate()); 368 369 v8::Local<v8::Script> script = 370 Compile(CcTest::isolate(), 371 "function a() {\n" 372 "var result = function(p,a,c,k,e,d)" 373 "{return p}(\"if blah blah\",62,1976,\'a|b\'.split(\'|\'),0,{})\n" 374 "}"); 375 CheckFunctionName(script, "return p", ""); 376 } 377 378 379 TEST(MultipleAssignments) { 380 CcTest::InitializeVM(); 381 v8::HandleScope scope(CcTest::isolate()); 382 383 v8::Local<v8::Script> script = 384 Compile(CcTest::isolate(), 385 "var fun1 = fun2 = function () { return 1; }\n" 386 "var bar1 = bar2 = bar3 = function () { return 2; }\n" 387 "foo1 = foo2 = function () { return 3; }\n" 388 "baz1 = baz2 = baz3 = function () { return 4; }"); 389 CheckFunctionName(script, "return 1", "fun2"); 390 CheckFunctionName(script, "return 2", "bar3"); 391 CheckFunctionName(script, "return 3", "foo2"); 392 CheckFunctionName(script, "return 4", "baz3"); 393 } 394 395 396 TEST(AsConstructorParameter) { 397 CcTest::InitializeVM(); 398 v8::HandleScope scope(CcTest::isolate()); 399 400 v8::Local<v8::Script> script = Compile( 401 CcTest::isolate(), 402 "function Foo() {}\n" 403 "var foo = new Foo(function() { return 1; })\n" 404 "var bar = new Foo(function() { return 2; }, function() { return 3; })"); 405 CheckFunctionName(script, "return 1", ""); 406 CheckFunctionName(script, "return 2", ""); 407 CheckFunctionName(script, "return 3", ""); 408 } 409 410 411 TEST(FactoryHashmap) { 412 CcTest::InitializeVM(); 413 v8::HandleScope scope(CcTest::isolate()); 414 415 v8::Local<v8::Script> script = 416 Compile(CcTest::isolate(), 417 "function createMyObj() {\n" 418 " var obj = {};\n" 419 " obj[\"method1\"] = function() { return 1; }\n" 420 " obj[\"method2\"] = function() { return 2; }\n" 421 " return obj;\n" 422 "}"); 423 CheckFunctionName(script, "return 1", "obj.method1"); 424 CheckFunctionName(script, "return 2", "obj.method2"); 425 } 426 427 428 TEST(FactoryHashmapVariable) { 429 CcTest::InitializeVM(); 430 v8::HandleScope scope(CcTest::isolate()); 431 432 v8::Local<v8::Script> script = 433 Compile(CcTest::isolate(), 434 "function createMyObj() {\n" 435 " var obj = {};\n" 436 " var methodName = \"method1\";\n" 437 " obj[methodName] = function() { return 1; }\n" 438 " methodName = \"method2\";\n" 439 " obj[methodName] = function() { return 2; }\n" 440 " return obj;\n" 441 "}"); 442 // Can't infer function names statically. 443 CheckFunctionName(script, "return 1", "obj.(anonymous function)"); 444 CheckFunctionName(script, "return 2", "obj.(anonymous function)"); 445 } 446 447 448 TEST(FactoryHashmapConditional) { 449 CcTest::InitializeVM(); 450 v8::HandleScope scope(CcTest::isolate()); 451 452 v8::Local<v8::Script> script = Compile( 453 CcTest::isolate(), 454 "function createMyObj() {\n" 455 " var obj = {};\n" 456 " obj[0 ? \"method1\" : \"method2\"] = function() { return 1; }\n" 457 " return obj;\n" 458 "}"); 459 // Can't infer the function name statically. 460 CheckFunctionName(script, "return 1", "obj.(anonymous function)"); 461 } 462 463 464 TEST(GlobalAssignmentAndCall) { 465 CcTest::InitializeVM(); 466 v8::HandleScope scope(CcTest::isolate()); 467 468 v8::Local<v8::Script> script = Compile(CcTest::isolate(), 469 "var Foo = function() {\n" 470 " return 1;\n" 471 "}();\n" 472 "var Baz = Bar = function() {\n" 473 " return 2;\n" 474 "}"); 475 // The inferred name is empty, because this is an assignment of a result. 476 CheckFunctionName(script, "return 1", ""); 477 // See MultipleAssignments test. 478 CheckFunctionName(script, "return 2", "Bar"); 479 } 480 481 482 TEST(AssignmentAndCall) { 483 CcTest::InitializeVM(); 484 v8::HandleScope scope(CcTest::isolate()); 485 486 v8::Local<v8::Script> script = Compile(CcTest::isolate(), 487 "(function Enclosing() {\n" 488 " var Foo;\n" 489 " Foo = function() {\n" 490 " return 1;\n" 491 " }();\n" 492 " var Baz = Bar = function() {\n" 493 " return 2;\n" 494 " }\n" 495 "})();"); 496 // The inferred name is empty, because this is an assignment of a result. 497 CheckFunctionName(script, "return 1", ""); 498 // See MultipleAssignments test. 499 // TODO(2276): Lazy compiling the enclosing outer closure would yield 500 // in "Enclosing.Bar" being the inferred name here. 501 CheckFunctionName(script, "return 2", "Bar"); 502 } 503 504 505 TEST(MethodAssignmentInAnonymousFunctionCall) { 506 CcTest::InitializeVM(); 507 v8::HandleScope scope(CcTest::isolate()); 508 509 v8::Local<v8::Script> script = 510 Compile(CcTest::isolate(), 511 "(function () {\n" 512 " var EventSource = function () { };\n" 513 " EventSource.prototype.addListener = function () {\n" 514 " return 2012;\n" 515 " };\n" 516 " this.PublicEventSource = EventSource;\n" 517 "})();"); 518 CheckFunctionName(script, "return 2012", "EventSource.addListener"); 519 } 520 521 522 TEST(ReturnAnonymousFunction) { 523 CcTest::InitializeVM(); 524 v8::HandleScope scope(CcTest::isolate()); 525 526 v8::Local<v8::Script> script = Compile(CcTest::isolate(), 527 "(function() {\n" 528 " function wrapCode() {\n" 529 " return function () {\n" 530 " return 2012;\n" 531 " };\n" 532 " };\n" 533 " var foo = 10;\n" 534 " function f() {\n" 535 " return wrapCode();\n" 536 " }\n" 537 " this.ref = f;\n" 538 "})()"); 539 script->Run(CcTest::isolate()->GetCurrentContext()).ToLocalChecked(); 540 CheckFunctionName(script, "return 2012", ""); 541 } 542