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