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