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 #include "v8.h" 29 30 #include "api.h" 31 #include "runtime.h" 32 #include "cctest.h" 33 34 35 using ::v8::internal::CStrVector; 36 using ::v8::internal::Factory; 37 using ::v8::internal::Handle; 38 using ::v8::internal::Heap; 39 using ::v8::internal::Isolate; 40 using ::v8::internal::JSFunction; 41 using ::v8::internal::Object; 42 using ::v8::internal::Runtime; 43 using ::v8::internal::Script; 44 using ::v8::internal::SmartArrayPointer; 45 using ::v8::internal::SharedFunctionInfo; 46 using ::v8::internal::String; 47 48 49 static v8::Persistent<v8::Context> env; 50 51 52 static void InitializeVM() { 53 if (env.IsEmpty()) { 54 v8::HandleScope scope; 55 env = v8::Context::New(); 56 } 57 v8::HandleScope scope; 58 env->Enter(); 59 } 60 61 62 static void CheckFunctionName(v8::Handle<v8::Script> script, 63 const char* func_pos_src, 64 const char* ref_inferred_name) { 65 // Get script source. 66 Handle<Object> obj = v8::Utils::OpenHandle(*script); 67 Handle<SharedFunctionInfo> shared_function; 68 if (obj->IsSharedFunctionInfo()) { 69 shared_function = 70 Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(*obj)); 71 } else { 72 shared_function = 73 Handle<SharedFunctionInfo>(JSFunction::cast(*obj)->shared()); 74 } 75 Handle<Script> i_script(Script::cast(shared_function->script())); 76 CHECK(i_script->source()->IsString()); 77 Handle<String> script_src(String::cast(i_script->source())); 78 79 // Find the position of a given func source substring in the source. 80 Handle<String> func_pos_str = 81 FACTORY->NewStringFromAscii(CStrVector(func_pos_src)); 82 int func_pos = Runtime::StringMatch(Isolate::Current(), 83 script_src, 84 func_pos_str, 85 0); 86 CHECK_NE(0, func_pos); 87 88 #ifdef ENABLE_DEBUGGER_SUPPORT 89 // Obtain SharedFunctionInfo for the function. 90 Object* shared_func_info_ptr = 91 Runtime::FindSharedFunctionInfoInScript(Isolate::Current(), 92 i_script, 93 func_pos); 94 CHECK(shared_func_info_ptr != HEAP->undefined_value()); 95 Handle<SharedFunctionInfo> shared_func_info( 96 SharedFunctionInfo::cast(shared_func_info_ptr)); 97 98 // Verify inferred function name. 99 SmartArrayPointer<char> inferred_name = 100 shared_func_info->inferred_name()->ToCString(); 101 CHECK_EQ(ref_inferred_name, *inferred_name); 102 #endif // ENABLE_DEBUGGER_SUPPORT 103 } 104 105 106 static v8::Handle<v8::Script> Compile(const char* src) { 107 return v8::Script::Compile(v8::String::New(src)); 108 } 109 110 111 TEST(GlobalProperty) { 112 InitializeVM(); 113 v8::HandleScope scope; 114 115 v8::Handle<v8::Script> script = Compile( 116 "fun1 = function() { return 1; }\n" 117 "fun2 = function() { return 2; }\n"); 118 CheckFunctionName(script, "return 1", "fun1"); 119 CheckFunctionName(script, "return 2", "fun2"); 120 } 121 122 123 TEST(GlobalVar) { 124 InitializeVM(); 125 v8::HandleScope scope; 126 127 v8::Handle<v8::Script> script = Compile( 128 "var fun1 = function() { return 1; }\n" 129 "var fun2 = function() { return 2; }\n"); 130 CheckFunctionName(script, "return 1", "fun1"); 131 CheckFunctionName(script, "return 2", "fun2"); 132 } 133 134 135 TEST(LocalVar) { 136 InitializeVM(); 137 v8::HandleScope scope; 138 139 v8::Handle<v8::Script> script = Compile( 140 "function outer() {\n" 141 " var fun1 = function() { return 1; }\n" 142 " var fun2 = function() { return 2; }\n" 143 "}"); 144 CheckFunctionName(script, "return 1", "fun1"); 145 CheckFunctionName(script, "return 2", "fun2"); 146 } 147 148 149 TEST(InConstructor) { 150 InitializeVM(); 151 v8::HandleScope scope; 152 153 v8::Handle<v8::Script> script = Compile( 154 "function MyClass() {\n" 155 " this.method1 = function() { return 1; }\n" 156 " this.method2 = function() { return 2; }\n" 157 "}"); 158 CheckFunctionName(script, "return 1", "MyClass.method1"); 159 CheckFunctionName(script, "return 2", "MyClass.method2"); 160 } 161 162 163 TEST(Factory) { 164 InitializeVM(); 165 v8::HandleScope scope; 166 167 v8::Handle<v8::Script> script = Compile( 168 "function createMyObj() {\n" 169 " var obj = {};\n" 170 " obj.method1 = function() { return 1; }\n" 171 " obj.method2 = function() { return 2; }\n" 172 " return obj;\n" 173 "}"); 174 CheckFunctionName(script, "return 1", "obj.method1"); 175 CheckFunctionName(script, "return 2", "obj.method2"); 176 } 177 178 179 TEST(Static) { 180 InitializeVM(); 181 v8::HandleScope scope; 182 183 v8::Handle<v8::Script> script = Compile( 184 "function MyClass() {}\n" 185 "MyClass.static1 = function() { return 1; }\n" 186 "MyClass.static2 = function() { return 2; }\n" 187 "MyClass.MyInnerClass = {}\n" 188 "MyClass.MyInnerClass.static3 = function() { return 3; }\n" 189 "MyClass.MyInnerClass.static4 = function() { return 4; }"); 190 CheckFunctionName(script, "return 1", "MyClass.static1"); 191 CheckFunctionName(script, "return 2", "MyClass.static2"); 192 CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.static3"); 193 CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.static4"); 194 } 195 196 197 TEST(Prototype) { 198 InitializeVM(); 199 v8::HandleScope scope; 200 201 v8::Handle<v8::Script> script = Compile( 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 InitializeVM(); 217 v8::HandleScope scope; 218 219 v8::Handle<v8::Script> script = Compile( 220 "function MyClass() {}\n" 221 "MyClass.prototype = {\n" 222 " method1: function() { return 1; },\n" 223 " method2: function() { return 2; } }"); 224 CheckFunctionName(script, "return 1", "MyClass.method1"); 225 CheckFunctionName(script, "return 2", "MyClass.method2"); 226 } 227 228 229 TEST(AsParameter) { 230 InitializeVM(); 231 v8::HandleScope scope; 232 233 v8::Handle<v8::Script> script = Compile( 234 "function f1(a) { return a(); }\n" 235 "function f2(a, b) { return a() + b(); }\n" 236 "var result1 = f1(function() { return 1; })\n" 237 "var result2 = f2(function() { return 2; }, function() { return 3; })"); 238 // Can't infer names here. 239 CheckFunctionName(script, "return 1", ""); 240 CheckFunctionName(script, "return 2", ""); 241 CheckFunctionName(script, "return 3", ""); 242 } 243 244 245 TEST(MultipleFuncsConditional) { 246 InitializeVM(); 247 v8::HandleScope scope; 248 249 v8::Handle<v8::Script> script = Compile( 250 "fun1 = 0 ?\n" 251 " function() { return 1; } :\n" 252 " function() { return 2; }"); 253 CheckFunctionName(script, "return 1", "fun1"); 254 CheckFunctionName(script, "return 2", "fun1"); 255 } 256 257 258 TEST(MultipleFuncsInLiteral) { 259 InitializeVM(); 260 v8::HandleScope scope; 261 262 v8::Handle<v8::Script> script = Compile( 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 272 // See http://code.google.com/p/v8/issues/detail?id=380 273 TEST(Issue380) { 274 InitializeVM(); 275 v8::HandleScope scope; 276 277 v8::Handle<v8::Script> script = Compile( 278 "function a() {\n" 279 "var result = function(p,a,c,k,e,d)" 280 "{return p}(\"if blah blah\",62,1976,\'a|b\'.split(\'|\'),0,{})\n" 281 "}"); 282 CheckFunctionName(script, "return p", ""); 283 } 284 285 286 TEST(MultipleAssignments) { 287 InitializeVM(); 288 v8::HandleScope scope; 289 290 v8::Handle<v8::Script> script = Compile( 291 "var fun1 = fun2 = function () { return 1; }\n" 292 "var bar1 = bar2 = bar3 = function () { return 2; }\n" 293 "foo1 = foo2 = function () { return 3; }\n" 294 "baz1 = baz2 = baz3 = function () { return 4; }"); 295 CheckFunctionName(script, "return 1", "fun2"); 296 CheckFunctionName(script, "return 2", "bar3"); 297 CheckFunctionName(script, "return 3", "foo2"); 298 CheckFunctionName(script, "return 4", "baz3"); 299 } 300 301 302 TEST(AsConstructorParameter) { 303 InitializeVM(); 304 v8::HandleScope scope; 305 306 v8::Handle<v8::Script> script = Compile( 307 "function Foo() {}\n" 308 "var foo = new Foo(function() { return 1; })\n" 309 "var bar = new Foo(function() { return 2; }, function() { return 3; })"); 310 CheckFunctionName(script, "return 1", ""); 311 CheckFunctionName(script, "return 2", ""); 312 CheckFunctionName(script, "return 3", ""); 313 } 314 315 316 TEST(FactoryHashmap) { 317 InitializeVM(); 318 v8::HandleScope scope; 319 320 v8::Handle<v8::Script> script = Compile( 321 "function createMyObj() {\n" 322 " var obj = {};\n" 323 " obj[\"method1\"] = function() { return 1; }\n" 324 " obj[\"method2\"] = function() { return 2; }\n" 325 " return obj;\n" 326 "}"); 327 CheckFunctionName(script, "return 1", "obj.method1"); 328 CheckFunctionName(script, "return 2", "obj.method2"); 329 } 330 331 332 TEST(FactoryHashmapVariable) { 333 InitializeVM(); 334 v8::HandleScope scope; 335 336 v8::Handle<v8::Script> script = Compile( 337 "function createMyObj() {\n" 338 " var obj = {};\n" 339 " var methodName = \"method1\";\n" 340 " obj[methodName] = function() { return 1; }\n" 341 " methodName = \"method2\";\n" 342 " obj[methodName] = function() { return 2; }\n" 343 " return obj;\n" 344 "}"); 345 // Can't infer function names statically. 346 CheckFunctionName(script, "return 1", "obj.(anonymous function)"); 347 CheckFunctionName(script, "return 2", "obj.(anonymous function)"); 348 } 349 350 351 TEST(FactoryHashmapConditional) { 352 InitializeVM(); 353 v8::HandleScope scope; 354 355 v8::Handle<v8::Script> script = Compile( 356 "function createMyObj() {\n" 357 " var obj = {};\n" 358 " obj[0 ? \"method1\" : \"method2\"] = function() { return 1; }\n" 359 " return obj;\n" 360 "}"); 361 // Can't infer the function name statically. 362 CheckFunctionName(script, "return 1", "obj.(anonymous function)"); 363 } 364 365 366 TEST(GlobalAssignmentAndCall) { 367 InitializeVM(); 368 v8::HandleScope scope; 369 370 v8::Handle<v8::Script> script = Compile( 371 "var Foo = function() {\n" 372 " return 1;\n" 373 "}();\n" 374 "var Baz = Bar = function() {\n" 375 " return 2;\n" 376 "}"); 377 // The inferred name is empty, because this is an assignment of a result. 378 CheckFunctionName(script, "return 1", ""); 379 // See MultipleAssignments test. 380 CheckFunctionName(script, "return 2", "Bar"); 381 } 382 383 384 TEST(AssignmentAndCall) { 385 InitializeVM(); 386 v8::HandleScope scope; 387 388 v8::Handle<v8::Script> script = Compile( 389 "(function Enclosing() {\n" 390 " var Foo;\n" 391 " Foo = function() {\n" 392 " return 1;\n" 393 " }();\n" 394 " var Baz = Bar = function() {\n" 395 " return 2;\n" 396 " }\n" 397 "})();"); 398 // The inferred name is empty, because this is an assignment of a result. 399 CheckFunctionName(script, "return 1", ""); 400 // See MultipleAssignments test. 401 CheckFunctionName(script, "return 2", "Enclosing.Bar"); 402 } 403