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 
CheckFunctionName(v8::Local<v8::Script> script,const char * func_pos_src,const char * ref_inferred_name)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 
Compile(v8::Isolate * isolate,const char * src)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 
TEST(GlobalProperty)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 
TEST(GlobalVar)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 
TEST(LocalVar)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 
TEST(InConstructor)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 
TEST(Factory)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 
TEST(Static)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 
TEST(Prototype)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 
TEST(ObjectLiteral)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 
TEST(UpperCaseClass)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 
TEST(LowerCaseClass)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 
TEST(AsParameter)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 
TEST(MultipleFuncsConditional)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 
TEST(MultipleFuncsInLiteral)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 
TEST(AnonymousInAnonymousClosure1)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 
TEST(AnonymousInAnonymousClosure2)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 
TEST(NamedInAnonymousClosure)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
TEST(Issue380)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 
TEST(MultipleAssignments)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 
TEST(AsConstructorParameter)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 
TEST(FactoryHashmap)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 
TEST(FactoryHashmapVariable)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 
TEST(FactoryHashmapConditional)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 
TEST(GlobalAssignmentAndCall)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 
TEST(AssignmentAndCall)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 
TEST(MethodAssignmentInAnonymousFunctionCall)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 
TEST(ReturnAnonymousFunction)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