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 "v8.h" 30 31 #include "api.h" 32 #include "debug.h" 33 #include "runtime.h" 34 #include "cctest.h" 35 36 37 using ::v8::internal::CStrVector; 38 using ::v8::internal::Factory; 39 using ::v8::internal::Handle; 40 using ::v8::internal::Heap; 41 using ::v8::internal::Isolate; 42 using ::v8::internal::JSFunction; 43 using ::v8::internal::Object; 44 using ::v8::internal::Runtime; 45 using ::v8::internal::Script; 46 using ::v8::internal::SmartArrayPointer; 47 using ::v8::internal::SharedFunctionInfo; 48 using ::v8::internal::String; 49 50 51 static void CheckFunctionName(v8::Handle<v8::Script> script, 52 const char* func_pos_src, 53 const char* ref_inferred_name) { 54 Isolate* isolate = Isolate::Current(); 55 Factory* factory = isolate->factory(); 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 Handle<String> func_pos_str = 73 factory->NewStringFromAscii(CStrVector(func_pos_src)); 74 int func_pos = Runtime::StringMatch(isolate, 75 script_src, 76 func_pos_str, 77 0); 78 CHECK_NE(0, func_pos); 79 80 #ifdef ENABLE_DEBUGGER_SUPPORT 81 // Obtain SharedFunctionInfo for the function. 82 isolate->debug()->PrepareForBreakPoints(); 83 Object* shared_func_info_ptr = 84 isolate->debug()->FindSharedFunctionInfoInScript(i_script, func_pos); 85 CHECK(shared_func_info_ptr != HEAP->undefined_value()); 86 Handle<SharedFunctionInfo> shared_func_info( 87 SharedFunctionInfo::cast(shared_func_info_ptr)); 88 89 // Verify inferred function name. 90 SmartArrayPointer<char> inferred_name = 91 shared_func_info->inferred_name()->ToCString(); 92 CHECK_EQ(ref_inferred_name, *inferred_name); 93 #endif // ENABLE_DEBUGGER_SUPPORT 94 } 95 96 97 static v8::Handle<v8::Script> Compile(const char* src) { 98 return v8::Script::Compile(v8::String::New(src)); 99 } 100 101 102 TEST(GlobalProperty) { 103 CcTest::InitializeVM(); 104 v8::HandleScope scope(CcTest::isolate()); 105 106 v8::Handle<v8::Script> script = Compile( 107 "fun1 = function() { return 1; }\n" 108 "fun2 = function() { return 2; }\n"); 109 CheckFunctionName(script, "return 1", "fun1"); 110 CheckFunctionName(script, "return 2", "fun2"); 111 } 112 113 114 TEST(GlobalVar) { 115 CcTest::InitializeVM(); 116 v8::HandleScope scope(CcTest::isolate()); 117 118 v8::Handle<v8::Script> script = Compile( 119 "var fun1 = function() { return 1; }\n" 120 "var fun2 = function() { return 2; }\n"); 121 CheckFunctionName(script, "return 1", "fun1"); 122 CheckFunctionName(script, "return 2", "fun2"); 123 } 124 125 126 TEST(LocalVar) { 127 CcTest::InitializeVM(); 128 v8::HandleScope scope(CcTest::isolate()); 129 130 v8::Handle<v8::Script> script = Compile( 131 "function outer() {\n" 132 " var fun1 = function() { return 1; }\n" 133 " var fun2 = function() { return 2; }\n" 134 "}"); 135 CheckFunctionName(script, "return 1", "fun1"); 136 CheckFunctionName(script, "return 2", "fun2"); 137 } 138 139 140 TEST(InConstructor) { 141 CcTest::InitializeVM(); 142 v8::HandleScope scope(CcTest::isolate()); 143 144 v8::Handle<v8::Script> script = Compile( 145 "function MyClass() {\n" 146 " this.method1 = function() { return 1; }\n" 147 " this.method2 = function() { return 2; }\n" 148 "}"); 149 CheckFunctionName(script, "return 1", "MyClass.method1"); 150 CheckFunctionName(script, "return 2", "MyClass.method2"); 151 } 152 153 154 TEST(Factory) { 155 CcTest::InitializeVM(); 156 v8::HandleScope scope(CcTest::isolate()); 157 158 v8::Handle<v8::Script> script = Compile( 159 "function createMyObj() {\n" 160 " var obj = {};\n" 161 " obj.method1 = function() { return 1; }\n" 162 " obj.method2 = function() { return 2; }\n" 163 " return obj;\n" 164 "}"); 165 CheckFunctionName(script, "return 1", "obj.method1"); 166 CheckFunctionName(script, "return 2", "obj.method2"); 167 } 168 169 170 TEST(Static) { 171 CcTest::InitializeVM(); 172 v8::HandleScope scope(CcTest::isolate()); 173 174 v8::Handle<v8::Script> script = Compile( 175 "function MyClass() {}\n" 176 "MyClass.static1 = function() { return 1; }\n" 177 "MyClass.static2 = function() { return 2; }\n" 178 "MyClass.MyInnerClass = {}\n" 179 "MyClass.MyInnerClass.static3 = function() { return 3; }\n" 180 "MyClass.MyInnerClass.static4 = function() { return 4; }"); 181 CheckFunctionName(script, "return 1", "MyClass.static1"); 182 CheckFunctionName(script, "return 2", "MyClass.static2"); 183 CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.static3"); 184 CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.static4"); 185 } 186 187 188 TEST(Prototype) { 189 CcTest::InitializeVM(); 190 v8::HandleScope scope(CcTest::isolate()); 191 192 v8::Handle<v8::Script> script = Compile( 193 "function MyClass() {}\n" 194 "MyClass.prototype.method1 = function() { return 1; }\n" 195 "MyClass.prototype.method2 = function() { return 2; }\n" 196 "MyClass.MyInnerClass = function() {}\n" 197 "MyClass.MyInnerClass.prototype.method3 = function() { return 3; }\n" 198 "MyClass.MyInnerClass.prototype.method4 = function() { return 4; }"); 199 CheckFunctionName(script, "return 1", "MyClass.method1"); 200 CheckFunctionName(script, "return 2", "MyClass.method2"); 201 CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.method3"); 202 CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.method4"); 203 } 204 205 206 TEST(ObjectLiteral) { 207 CcTest::InitializeVM(); 208 v8::HandleScope scope(CcTest::isolate()); 209 210 v8::Handle<v8::Script> script = Compile( 211 "function MyClass() {}\n" 212 "MyClass.prototype = {\n" 213 " method1: function() { return 1; },\n" 214 " method2: function() { return 2; } }"); 215 CheckFunctionName(script, "return 1", "MyClass.method1"); 216 CheckFunctionName(script, "return 2", "MyClass.method2"); 217 } 218 219 220 TEST(AsParameter) { 221 CcTest::InitializeVM(); 222 v8::HandleScope scope(CcTest::isolate()); 223 224 v8::Handle<v8::Script> script = Compile( 225 "function f1(a) { return a(); }\n" 226 "function f2(a, b) { return a() + b(); }\n" 227 "var result1 = f1(function() { return 1; })\n" 228 "var result2 = f2(function() { return 2; }, function() { return 3; })"); 229 // Can't infer names here. 230 CheckFunctionName(script, "return 1", ""); 231 CheckFunctionName(script, "return 2", ""); 232 CheckFunctionName(script, "return 3", ""); 233 } 234 235 236 TEST(MultipleFuncsConditional) { 237 CcTest::InitializeVM(); 238 v8::HandleScope scope(CcTest::isolate()); 239 240 v8::Handle<v8::Script> script = Compile( 241 "fun1 = 0 ?\n" 242 " function() { return 1; } :\n" 243 " function() { return 2; }"); 244 CheckFunctionName(script, "return 1", "fun1"); 245 CheckFunctionName(script, "return 2", "fun1"); 246 } 247 248 249 TEST(MultipleFuncsInLiteral) { 250 CcTest::InitializeVM(); 251 v8::HandleScope scope(CcTest::isolate()); 252 253 v8::Handle<v8::Script> script = Compile( 254 "function MyClass() {}\n" 255 "MyClass.prototype = {\n" 256 " method1: 0 ? function() { return 1; } :\n" 257 " function() { return 2; } }"); 258 CheckFunctionName(script, "return 1", "MyClass.method1"); 259 CheckFunctionName(script, "return 2", "MyClass.method1"); 260 } 261 262 263 TEST(AnonymousInAnonymousClosure1) { 264 CcTest::InitializeVM(); 265 v8::HandleScope scope(CcTest::isolate()); 266 267 v8::Handle<v8::Script> script = Compile( 268 "(function() {\n" 269 " (function() {\n" 270 " var a = 1;\n" 271 " return;\n" 272 " })();\n" 273 " var b = function() {\n" 274 " var c = 1;\n" 275 " return;\n" 276 " };\n" 277 "})();"); 278 CheckFunctionName(script, "return", ""); 279 } 280 281 282 TEST(AnonymousInAnonymousClosure2) { 283 CcTest::InitializeVM(); 284 v8::HandleScope scope(CcTest::isolate()); 285 286 v8::Handle<v8::Script> script = Compile( 287 "(function() {\n" 288 " (function() {\n" 289 " var a = 1;\n" 290 " return;\n" 291 " })();\n" 292 " var c = 1;\n" 293 "})();"); 294 CheckFunctionName(script, "return", ""); 295 } 296 297 298 TEST(NamedInAnonymousClosure) { 299 CcTest::InitializeVM(); 300 v8::HandleScope scope(CcTest::isolate()); 301 302 v8::Handle<v8::Script> script = Compile( 303 "var foo = function() {\n" 304 " (function named() {\n" 305 " var a = 1;\n" 306 " })();\n" 307 " var c = 1;\n" 308 " return;\n" 309 "};"); 310 CheckFunctionName(script, "return", "foo"); 311 } 312 313 314 // See http://code.google.com/p/v8/issues/detail?id=380 315 TEST(Issue380) { 316 CcTest::InitializeVM(); 317 v8::HandleScope scope(CcTest::isolate()); 318 319 v8::Handle<v8::Script> script = Compile( 320 "function a() {\n" 321 "var result = function(p,a,c,k,e,d)" 322 "{return p}(\"if blah blah\",62,1976,\'a|b\'.split(\'|\'),0,{})\n" 323 "}"); 324 CheckFunctionName(script, "return p", ""); 325 } 326 327 328 TEST(MultipleAssignments) { 329 CcTest::InitializeVM(); 330 v8::HandleScope scope(CcTest::isolate()); 331 332 v8::Handle<v8::Script> script = Compile( 333 "var fun1 = fun2 = function () { return 1; }\n" 334 "var bar1 = bar2 = bar3 = function () { return 2; }\n" 335 "foo1 = foo2 = function () { return 3; }\n" 336 "baz1 = baz2 = baz3 = function () { return 4; }"); 337 CheckFunctionName(script, "return 1", "fun2"); 338 CheckFunctionName(script, "return 2", "bar3"); 339 CheckFunctionName(script, "return 3", "foo2"); 340 CheckFunctionName(script, "return 4", "baz3"); 341 } 342 343 344 TEST(AsConstructorParameter) { 345 CcTest::InitializeVM(); 346 v8::HandleScope scope(CcTest::isolate()); 347 348 v8::Handle<v8::Script> script = Compile( 349 "function Foo() {}\n" 350 "var foo = new Foo(function() { return 1; })\n" 351 "var bar = new Foo(function() { return 2; }, function() { return 3; })"); 352 CheckFunctionName(script, "return 1", ""); 353 CheckFunctionName(script, "return 2", ""); 354 CheckFunctionName(script, "return 3", ""); 355 } 356 357 358 TEST(FactoryHashmap) { 359 CcTest::InitializeVM(); 360 v8::HandleScope scope(CcTest::isolate()); 361 362 v8::Handle<v8::Script> script = Compile( 363 "function createMyObj() {\n" 364 " var obj = {};\n" 365 " obj[\"method1\"] = function() { return 1; }\n" 366 " obj[\"method2\"] = function() { return 2; }\n" 367 " return obj;\n" 368 "}"); 369 CheckFunctionName(script, "return 1", "obj.method1"); 370 CheckFunctionName(script, "return 2", "obj.method2"); 371 } 372 373 374 TEST(FactoryHashmapVariable) { 375 CcTest::InitializeVM(); 376 v8::HandleScope scope(CcTest::isolate()); 377 378 v8::Handle<v8::Script> script = Compile( 379 "function createMyObj() {\n" 380 " var obj = {};\n" 381 " var methodName = \"method1\";\n" 382 " obj[methodName] = function() { return 1; }\n" 383 " methodName = \"method2\";\n" 384 " obj[methodName] = function() { return 2; }\n" 385 " return obj;\n" 386 "}"); 387 // Can't infer function names statically. 388 CheckFunctionName(script, "return 1", "obj.(anonymous function)"); 389 CheckFunctionName(script, "return 2", "obj.(anonymous function)"); 390 } 391 392 393 TEST(FactoryHashmapConditional) { 394 CcTest::InitializeVM(); 395 v8::HandleScope scope(CcTest::isolate()); 396 397 v8::Handle<v8::Script> script = Compile( 398 "function createMyObj() {\n" 399 " var obj = {};\n" 400 " obj[0 ? \"method1\" : \"method2\"] = function() { return 1; }\n" 401 " return obj;\n" 402 "}"); 403 // Can't infer the function name statically. 404 CheckFunctionName(script, "return 1", "obj.(anonymous function)"); 405 } 406 407 408 TEST(GlobalAssignmentAndCall) { 409 CcTest::InitializeVM(); 410 v8::HandleScope scope(CcTest::isolate()); 411 412 v8::Handle<v8::Script> script = Compile( 413 "var Foo = function() {\n" 414 " return 1;\n" 415 "}();\n" 416 "var Baz = Bar = function() {\n" 417 " return 2;\n" 418 "}"); 419 // The inferred name is empty, because this is an assignment of a result. 420 CheckFunctionName(script, "return 1", ""); 421 // See MultipleAssignments test. 422 CheckFunctionName(script, "return 2", "Bar"); 423 } 424 425 426 TEST(AssignmentAndCall) { 427 CcTest::InitializeVM(); 428 v8::HandleScope scope(CcTest::isolate()); 429 430 v8::Handle<v8::Script> script = Compile( 431 "(function Enclosing() {\n" 432 " var Foo;\n" 433 " Foo = function() {\n" 434 " return 1;\n" 435 " }();\n" 436 " var Baz = Bar = function() {\n" 437 " return 2;\n" 438 " }\n" 439 "})();"); 440 // The inferred name is empty, because this is an assignment of a result. 441 CheckFunctionName(script, "return 1", ""); 442 // See MultipleAssignments test. 443 // TODO(2276): Lazy compiling the enclosing outer closure would yield 444 // in "Enclosing.Bar" being the inferred name here. 445 CheckFunctionName(script, "return 2", "Bar"); 446 } 447 448 449 TEST(MethodAssignmentInAnonymousFunctionCall) { 450 CcTest::InitializeVM(); 451 v8::HandleScope scope(CcTest::isolate()); 452 453 v8::Handle<v8::Script> script = Compile( 454 "(function () {\n" 455 " var EventSource = function () { };\n" 456 " EventSource.prototype.addListener = function () {\n" 457 " return 2012;\n" 458 " };\n" 459 " this.PublicEventSource = EventSource;\n" 460 "})();"); 461 CheckFunctionName(script, "return 2012", "EventSource.addListener"); 462 } 463 464 465 TEST(ReturnAnonymousFunction) { 466 CcTest::InitializeVM(); 467 v8::HandleScope scope(CcTest::isolate()); 468 469 v8::Handle<v8::Script> script = Compile( 470 "(function() {\n" 471 " function wrapCode() {\n" 472 " return function () {\n" 473 " return 2012;\n" 474 " };\n" 475 " };\n" 476 " var foo = 10;\n" 477 " function f() {\n" 478 " return wrapCode();\n" 479 " }\n" 480 " this.ref = f;\n" 481 "})()"); 482 script->Run(); 483 CheckFunctionName(script, "return 2012", ""); 484 } 485