24f9c73532fee85aca402c808732841f0528b78b
[platform/upstream/nodejs.git] / deps / v8 / test / cctest / test-func-name-inference.cc
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/string-search.h"
34 #include "test/cctest/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 using ::v8::internal::Vector;
50
51
52 static void CheckFunctionName(v8::Handle<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   isolate->debug()->PrepareForBreakPoints();
84   Object* shared_func_info_ptr =
85       isolate->debug()->FindSharedFunctionInfoInScript(i_script, func_pos);
86   CHECK(shared_func_info_ptr != CcTest::heap()->undefined_value());
87   Handle<SharedFunctionInfo> shared_func_info(
88       SharedFunctionInfo::cast(shared_func_info_ptr));
89
90   // Verify inferred function name.
91   SmartArrayPointer<char> inferred_name =
92       shared_func_info->inferred_name()->ToCString();
93   CHECK_EQ(0, strcmp(ref_inferred_name, inferred_name.get()));
94 }
95
96
97 static v8::Handle<v8::Script> Compile(v8::Isolate* isolate, const char* src) {
98   return v8::Script::Compile(v8::String::NewFromUtf8(isolate, 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       CcTest::isolate(),
108       "fun1 = function() { return 1; }\n"
109       "fun2 = function() { return 2; }\n");
110   CheckFunctionName(script, "return 1", "fun1");
111   CheckFunctionName(script, "return 2", "fun2");
112 }
113
114
115 TEST(GlobalVar) {
116   CcTest::InitializeVM();
117   v8::HandleScope scope(CcTest::isolate());
118
119   v8::Handle<v8::Script> script = Compile(
120       CcTest::isolate(),
121       "var fun1 = function() { return 1; }\n"
122       "var fun2 = function() { return 2; }\n");
123   CheckFunctionName(script, "return 1", "fun1");
124   CheckFunctionName(script, "return 2", "fun2");
125 }
126
127
128 TEST(LocalVar) {
129   CcTest::InitializeVM();
130   v8::HandleScope scope(CcTest::isolate());
131
132   v8::Handle<v8::Script> script = Compile(
133       CcTest::isolate(),
134       "function outer() {\n"
135       "  var fun1 = function() { return 1; }\n"
136       "  var fun2 = function() { return 2; }\n"
137       "}");
138   CheckFunctionName(script, "return 1", "fun1");
139   CheckFunctionName(script, "return 2", "fun2");
140 }
141
142
143 TEST(InConstructor) {
144   CcTest::InitializeVM();
145   v8::HandleScope scope(CcTest::isolate());
146
147   v8::Handle<v8::Script> script = Compile(
148       CcTest::isolate(),
149       "function MyClass() {\n"
150       "  this.method1 = function() { return 1; }\n"
151       "  this.method2 = function() { return 2; }\n"
152       "}");
153   CheckFunctionName(script, "return 1", "MyClass.method1");
154   CheckFunctionName(script, "return 2", "MyClass.method2");
155 }
156
157
158 TEST(Factory) {
159   CcTest::InitializeVM();
160   v8::HandleScope scope(CcTest::isolate());
161
162   v8::Handle<v8::Script> script = Compile(
163       CcTest::isolate(),
164       "function createMyObj() {\n"
165       "  var obj = {};\n"
166       "  obj.method1 = function() { return 1; }\n"
167       "  obj.method2 = function() { return 2; }\n"
168       "  return obj;\n"
169       "}");
170   CheckFunctionName(script, "return 1", "obj.method1");
171   CheckFunctionName(script, "return 2", "obj.method2");
172 }
173
174
175 TEST(Static) {
176   CcTest::InitializeVM();
177   v8::HandleScope scope(CcTest::isolate());
178
179   v8::Handle<v8::Script> script = Compile(
180       CcTest::isolate(),
181       "function MyClass() {}\n"
182       "MyClass.static1 = function() { return 1; }\n"
183       "MyClass.static2 = function() { return 2; }\n"
184       "MyClass.MyInnerClass = {}\n"
185       "MyClass.MyInnerClass.static3 = function() { return 3; }\n"
186       "MyClass.MyInnerClass.static4 = function() { return 4; }");
187   CheckFunctionName(script, "return 1", "MyClass.static1");
188   CheckFunctionName(script, "return 2", "MyClass.static2");
189   CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.static3");
190   CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.static4");
191 }
192
193
194 TEST(Prototype) {
195   CcTest::InitializeVM();
196   v8::HandleScope scope(CcTest::isolate());
197
198   v8::Handle<v8::Script> script = Compile(
199       CcTest::isolate(),
200       "function MyClass() {}\n"
201       "MyClass.prototype.method1 = function() { return 1; }\n"
202       "MyClass.prototype.method2 = function() { return 2; }\n"
203       "MyClass.MyInnerClass = function() {}\n"
204       "MyClass.MyInnerClass.prototype.method3 = function() { return 3; }\n"
205       "MyClass.MyInnerClass.prototype.method4 = function() { return 4; }");
206   CheckFunctionName(script, "return 1", "MyClass.method1");
207   CheckFunctionName(script, "return 2", "MyClass.method2");
208   CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.method3");
209   CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.method4");
210 }
211
212
213 TEST(ObjectLiteral) {
214   CcTest::InitializeVM();
215   v8::HandleScope scope(CcTest::isolate());
216
217   v8::Handle<v8::Script> script = Compile(
218       CcTest::isolate(),
219       "function MyClass() {}\n"
220       "MyClass.prototype = {\n"
221       "  method1: function() { return 1; },\n"
222       "  method2: function() { return 2; } }");
223   CheckFunctionName(script, "return 1", "MyClass.method1");
224   CheckFunctionName(script, "return 2", "MyClass.method2");
225 }
226
227
228 TEST(AsParameter) {
229   CcTest::InitializeVM();
230   v8::HandleScope scope(CcTest::isolate());
231
232   v8::Handle<v8::Script> script = Compile(
233       CcTest::isolate(),
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   CcTest::InitializeVM();
247   v8::HandleScope scope(CcTest::isolate());
248
249   v8::Handle<v8::Script> script = Compile(
250       CcTest::isolate(),
251       "fun1 = 0 ?\n"
252       "    function() { return 1; } :\n"
253       "    function() { return 2; }");
254   CheckFunctionName(script, "return 1", "fun1");
255   CheckFunctionName(script, "return 2", "fun1");
256 }
257
258
259 TEST(MultipleFuncsInLiteral) {
260   CcTest::InitializeVM();
261   v8::HandleScope scope(CcTest::isolate());
262
263   v8::Handle<v8::Script> script = Compile(
264       CcTest::isolate(),
265       "function MyClass() {}\n"
266       "MyClass.prototype = {\n"
267       "  method1: 0 ? function() { return 1; } :\n"
268       "               function() { return 2; } }");
269   CheckFunctionName(script, "return 1", "MyClass.method1");
270   CheckFunctionName(script, "return 2", "MyClass.method1");
271 }
272
273
274 TEST(AnonymousInAnonymousClosure1) {
275   CcTest::InitializeVM();
276   v8::HandleScope scope(CcTest::isolate());
277
278   v8::Handle<v8::Script> script = Compile(
279       CcTest::isolate(),
280       "(function() {\n"
281       "  (function() {\n"
282       "      var a = 1;\n"
283       "      return;\n"
284       "  })();\n"
285       "  var b = function() {\n"
286       "      var c = 1;\n"
287       "      return;\n"
288       "  };\n"
289       "})();");
290   CheckFunctionName(script, "return", "");
291 }
292
293
294 TEST(AnonymousInAnonymousClosure2) {
295   CcTest::InitializeVM();
296   v8::HandleScope scope(CcTest::isolate());
297
298   v8::Handle<v8::Script> script = Compile(
299       CcTest::isolate(),
300       "(function() {\n"
301       "  (function() {\n"
302       "      var a = 1;\n"
303       "      return;\n"
304       "  })();\n"
305       "  var c = 1;\n"
306       "})();");
307   CheckFunctionName(script, "return", "");
308 }
309
310
311 TEST(NamedInAnonymousClosure) {
312   CcTest::InitializeVM();
313   v8::HandleScope scope(CcTest::isolate());
314
315   v8::Handle<v8::Script> script = Compile(
316       CcTest::isolate(),
317       "var foo = function() {\n"
318       "  (function named() {\n"
319       "      var a = 1;\n"
320       "  })();\n"
321       "  var c = 1;\n"
322       "  return;\n"
323       "};");
324   CheckFunctionName(script, "return", "foo");
325 }
326
327
328 // See http://code.google.com/p/v8/issues/detail?id=380
329 TEST(Issue380) {
330   CcTest::InitializeVM();
331   v8::HandleScope scope(CcTest::isolate());
332
333   v8::Handle<v8::Script> script = Compile(
334       CcTest::isolate(),
335       "function a() {\n"
336       "var result = function(p,a,c,k,e,d)"
337       "{return p}(\"if blah blah\",62,1976,\'a|b\'.split(\'|\'),0,{})\n"
338       "}");
339   CheckFunctionName(script, "return p", "");
340 }
341
342
343 TEST(MultipleAssignments) {
344   CcTest::InitializeVM();
345   v8::HandleScope scope(CcTest::isolate());
346
347   v8::Handle<v8::Script> script = Compile(
348       CcTest::isolate(),
349       "var fun1 = fun2 = function () { return 1; }\n"
350       "var bar1 = bar2 = bar3 = function () { return 2; }\n"
351       "foo1 = foo2 = function () { return 3; }\n"
352       "baz1 = baz2 = baz3 = function () { return 4; }");
353   CheckFunctionName(script, "return 1", "fun2");
354   CheckFunctionName(script, "return 2", "bar3");
355   CheckFunctionName(script, "return 3", "foo2");
356   CheckFunctionName(script, "return 4", "baz3");
357 }
358
359
360 TEST(AsConstructorParameter) {
361   CcTest::InitializeVM();
362   v8::HandleScope scope(CcTest::isolate());
363
364   v8::Handle<v8::Script> script = Compile(
365       CcTest::isolate(),
366       "function Foo() {}\n"
367       "var foo = new Foo(function() { return 1; })\n"
368       "var bar = new Foo(function() { return 2; }, function() { return 3; })");
369   CheckFunctionName(script, "return 1", "");
370   CheckFunctionName(script, "return 2", "");
371   CheckFunctionName(script, "return 3", "");
372 }
373
374
375 TEST(FactoryHashmap) {
376   CcTest::InitializeVM();
377   v8::HandleScope scope(CcTest::isolate());
378
379   v8::Handle<v8::Script> script = Compile(
380       CcTest::isolate(),
381       "function createMyObj() {\n"
382       "  var obj = {};\n"
383       "  obj[\"method1\"] = function() { return 1; }\n"
384       "  obj[\"method2\"] = function() { return 2; }\n"
385       "  return obj;\n"
386       "}");
387   CheckFunctionName(script, "return 1", "obj.method1");
388   CheckFunctionName(script, "return 2", "obj.method2");
389 }
390
391
392 TEST(FactoryHashmapVariable) {
393   CcTest::InitializeVM();
394   v8::HandleScope scope(CcTest::isolate());
395
396   v8::Handle<v8::Script> script = Compile(
397       CcTest::isolate(),
398       "function createMyObj() {\n"
399       "  var obj = {};\n"
400       "  var methodName = \"method1\";\n"
401       "  obj[methodName] = function() { return 1; }\n"
402       "  methodName = \"method2\";\n"
403       "  obj[methodName] = function() { return 2; }\n"
404       "  return obj;\n"
405       "}");
406   // Can't infer function names statically.
407   CheckFunctionName(script, "return 1", "obj.(anonymous function)");
408   CheckFunctionName(script, "return 2", "obj.(anonymous function)");
409 }
410
411
412 TEST(FactoryHashmapConditional) {
413   CcTest::InitializeVM();
414   v8::HandleScope scope(CcTest::isolate());
415
416   v8::Handle<v8::Script> script = Compile(
417       CcTest::isolate(),
418       "function createMyObj() {\n"
419       "  var obj = {};\n"
420       "  obj[0 ? \"method1\" : \"method2\"] = function() { return 1; }\n"
421       "  return obj;\n"
422       "}");
423   // Can't infer the function name statically.
424   CheckFunctionName(script, "return 1", "obj.(anonymous function)");
425 }
426
427
428 TEST(GlobalAssignmentAndCall) {
429   CcTest::InitializeVM();
430   v8::HandleScope scope(CcTest::isolate());
431
432   v8::Handle<v8::Script> script = Compile(
433       CcTest::isolate(),
434       "var Foo = function() {\n"
435       "  return 1;\n"
436       "}();\n"
437       "var Baz = Bar = function() {\n"
438       "  return 2;\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   CheckFunctionName(script, "return 2", "Bar");
444 }
445
446
447 TEST(AssignmentAndCall) {
448   CcTest::InitializeVM();
449   v8::HandleScope scope(CcTest::isolate());
450
451   v8::Handle<v8::Script> script = Compile(
452       CcTest::isolate(),
453       "(function Enclosing() {\n"
454       "  var Foo;\n"
455       "  Foo = function() {\n"
456       "    return 1;\n"
457       "  }();\n"
458       "  var Baz = Bar = function() {\n"
459       "    return 2;\n"
460       "  }\n"
461       "})();");
462   // The inferred name is empty, because this is an assignment of a result.
463   CheckFunctionName(script, "return 1", "");
464   // See MultipleAssignments test.
465   // TODO(2276): Lazy compiling the enclosing outer closure would yield
466   // in "Enclosing.Bar" being the inferred name here.
467   CheckFunctionName(script, "return 2", "Bar");
468 }
469
470
471 TEST(MethodAssignmentInAnonymousFunctionCall) {
472   CcTest::InitializeVM();
473   v8::HandleScope scope(CcTest::isolate());
474
475   v8::Handle<v8::Script> script = Compile(
476       CcTest::isolate(),
477       "(function () {\n"
478       "    var EventSource = function () { };\n"
479       "    EventSource.prototype.addListener = function () {\n"
480       "        return 2012;\n"
481       "    };\n"
482       "    this.PublicEventSource = EventSource;\n"
483       "})();");
484   CheckFunctionName(script, "return 2012", "EventSource.addListener");
485 }
486
487
488 TEST(ReturnAnonymousFunction) {
489   CcTest::InitializeVM();
490   v8::HandleScope scope(CcTest::isolate());
491
492   v8::Handle<v8::Script> script = Compile(
493       CcTest::isolate(),
494       "(function() {\n"
495       "  function wrapCode() {\n"
496       "    return function () {\n"
497       "      return 2012;\n"
498       "    };\n"
499       "  };\n"
500       "  var foo = 10;\n"
501       "  function f() {\n"
502       "    return wrapCode();\n"
503       "  }\n"
504       "  this.ref = f;\n"
505       "})()");
506   script->Run();
507   CheckFunctionName(script, "return 2012", "");
508 }