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 "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