Home | History | Annotate | Download | only in cctest
      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