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#include "v8.h"
29
30#include "api.h"
31#include "runtime.h"
32#include "cctest.h"
33
34
35using ::v8::internal::CStrVector;
36using ::v8::internal::Factory;
37using ::v8::internal::Handle;
38using ::v8::internal::Heap;
39using ::v8::internal::Isolate;
40using ::v8::internal::JSFunction;
41using ::v8::internal::Object;
42using ::v8::internal::Runtime;
43using ::v8::internal::Script;
44using ::v8::internal::SmartArrayPointer;
45using ::v8::internal::SharedFunctionInfo;
46using ::v8::internal::String;
47
48
49static v8::Persistent<v8::Context> env;
50
51
52static void InitializeVM() {
53  if (env.IsEmpty()) {
54    v8::HandleScope scope;
55    env = v8::Context::New();
56  }
57  v8::HandleScope scope;
58  env->Enter();
59}
60
61
62static void CheckFunctionName(v8::Handle<v8::Script> script,
63                              const char* func_pos_src,
64                              const char* ref_inferred_name) {
65  // Get script source.
66  Handle<Object> obj = v8::Utils::OpenHandle(*script);
67  Handle<SharedFunctionInfo> shared_function;
68  if (obj->IsSharedFunctionInfo()) {
69    shared_function =
70        Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(*obj));
71  } else {
72    shared_function =
73        Handle<SharedFunctionInfo>(JSFunction::cast(*obj)->shared());
74  }
75  Handle<Script> i_script(Script::cast(shared_function->script()));
76  CHECK(i_script->source()->IsString());
77  Handle<String> script_src(String::cast(i_script->source()));
78
79  // Find the position of a given func source substring in the source.
80  Handle<String> func_pos_str =
81      FACTORY->NewStringFromAscii(CStrVector(func_pos_src));
82  int func_pos = Runtime::StringMatch(Isolate::Current(),
83                                      script_src,
84                                      func_pos_str,
85                                      0);
86  CHECK_NE(0, func_pos);
87
88#ifdef ENABLE_DEBUGGER_SUPPORT
89  // Obtain SharedFunctionInfo for the function.
90  Object* shared_func_info_ptr =
91      Runtime::FindSharedFunctionInfoInScript(Isolate::Current(),
92                                              i_script,
93                                              func_pos);
94  CHECK(shared_func_info_ptr != HEAP->undefined_value());
95  Handle<SharedFunctionInfo> shared_func_info(
96      SharedFunctionInfo::cast(shared_func_info_ptr));
97
98  // Verify inferred function name.
99  SmartArrayPointer<char> inferred_name =
100      shared_func_info->inferred_name()->ToCString();
101  CHECK_EQ(ref_inferred_name, *inferred_name);
102#endif  // ENABLE_DEBUGGER_SUPPORT
103}
104
105
106static v8::Handle<v8::Script> Compile(const char* src) {
107  return v8::Script::Compile(v8::String::New(src));
108}
109
110
111TEST(GlobalProperty) {
112  InitializeVM();
113  v8::HandleScope scope;
114
115  v8::Handle<v8::Script> script = Compile(
116      "fun1 = function() { return 1; }\n"
117      "fun2 = function() { return 2; }\n");
118  CheckFunctionName(script, "return 1", "fun1");
119  CheckFunctionName(script, "return 2", "fun2");
120}
121
122
123TEST(GlobalVar) {
124  InitializeVM();
125  v8::HandleScope scope;
126
127  v8::Handle<v8::Script> script = Compile(
128      "var fun1 = function() { return 1; }\n"
129      "var fun2 = function() { return 2; }\n");
130  CheckFunctionName(script, "return 1", "fun1");
131  CheckFunctionName(script, "return 2", "fun2");
132}
133
134
135TEST(LocalVar) {
136  InitializeVM();
137  v8::HandleScope scope;
138
139  v8::Handle<v8::Script> script = Compile(
140      "function outer() {\n"
141      "  var fun1 = function() { return 1; }\n"
142      "  var fun2 = function() { return 2; }\n"
143      "}");
144  CheckFunctionName(script, "return 1", "fun1");
145  CheckFunctionName(script, "return 2", "fun2");
146}
147
148
149TEST(InConstructor) {
150  InitializeVM();
151  v8::HandleScope scope;
152
153  v8::Handle<v8::Script> script = Compile(
154      "function MyClass() {\n"
155      "  this.method1 = function() { return 1; }\n"
156      "  this.method2 = function() { return 2; }\n"
157      "}");
158  CheckFunctionName(script, "return 1", "MyClass.method1");
159  CheckFunctionName(script, "return 2", "MyClass.method2");
160}
161
162
163TEST(Factory) {
164  InitializeVM();
165  v8::HandleScope scope;
166
167  v8::Handle<v8::Script> script = Compile(
168      "function createMyObj() {\n"
169      "  var obj = {};\n"
170      "  obj.method1 = function() { return 1; }\n"
171      "  obj.method2 = function() { return 2; }\n"
172      "  return obj;\n"
173      "}");
174  CheckFunctionName(script, "return 1", "obj.method1");
175  CheckFunctionName(script, "return 2", "obj.method2");
176}
177
178
179TEST(Static) {
180  InitializeVM();
181  v8::HandleScope scope;
182
183  v8::Handle<v8::Script> script = Compile(
184      "function MyClass() {}\n"
185      "MyClass.static1 = function() { return 1; }\n"
186      "MyClass.static2 = function() { return 2; }\n"
187      "MyClass.MyInnerClass = {}\n"
188      "MyClass.MyInnerClass.static3 = function() { return 3; }\n"
189      "MyClass.MyInnerClass.static4 = function() { return 4; }");
190  CheckFunctionName(script, "return 1", "MyClass.static1");
191  CheckFunctionName(script, "return 2", "MyClass.static2");
192  CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.static3");
193  CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.static4");
194}
195
196
197TEST(Prototype) {
198  InitializeVM();
199  v8::HandleScope scope;
200
201  v8::Handle<v8::Script> script = Compile(
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
215TEST(ObjectLiteral) {
216  InitializeVM();
217  v8::HandleScope scope;
218
219  v8::Handle<v8::Script> script = Compile(
220      "function MyClass() {}\n"
221      "MyClass.prototype = {\n"
222      "  method1: function() { return 1; },\n"
223      "  method2: function() { return 2; } }");
224  CheckFunctionName(script, "return 1", "MyClass.method1");
225  CheckFunctionName(script, "return 2", "MyClass.method2");
226}
227
228
229TEST(AsParameter) {
230  InitializeVM();
231  v8::HandleScope scope;
232
233  v8::Handle<v8::Script> script = Compile(
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
245TEST(MultipleFuncsConditional) {
246  InitializeVM();
247  v8::HandleScope scope;
248
249  v8::Handle<v8::Script> script = Compile(
250      "fun1 = 0 ?\n"
251      "    function() { return 1; } :\n"
252      "    function() { return 2; }");
253  CheckFunctionName(script, "return 1", "fun1");
254  CheckFunctionName(script, "return 2", "fun1");
255}
256
257
258TEST(MultipleFuncsInLiteral) {
259  InitializeVM();
260  v8::HandleScope scope;
261
262  v8::Handle<v8::Script> script = Compile(
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
272// See http://code.google.com/p/v8/issues/detail?id=380
273TEST(Issue380) {
274  InitializeVM();
275  v8::HandleScope scope;
276
277  v8::Handle<v8::Script> script = Compile(
278      "function a() {\n"
279      "var result = function(p,a,c,k,e,d)"
280      "{return p}(\"if blah blah\",62,1976,\'a|b\'.split(\'|\'),0,{})\n"
281      "}");
282  CheckFunctionName(script, "return p", "");
283}
284
285
286TEST(MultipleAssignments) {
287  InitializeVM();
288  v8::HandleScope scope;
289
290  v8::Handle<v8::Script> script = Compile(
291      "var fun1 = fun2 = function () { return 1; }\n"
292      "var bar1 = bar2 = bar3 = function () { return 2; }\n"
293      "foo1 = foo2 = function () { return 3; }\n"
294      "baz1 = baz2 = baz3 = function () { return 4; }");
295  CheckFunctionName(script, "return 1", "fun2");
296  CheckFunctionName(script, "return 2", "bar3");
297  CheckFunctionName(script, "return 3", "foo2");
298  CheckFunctionName(script, "return 4", "baz3");
299}
300
301
302TEST(AsConstructorParameter) {
303  InitializeVM();
304  v8::HandleScope scope;
305
306  v8::Handle<v8::Script> script = Compile(
307      "function Foo() {}\n"
308      "var foo = new Foo(function() { return 1; })\n"
309      "var bar = new Foo(function() { return 2; }, function() { return 3; })");
310  CheckFunctionName(script, "return 1", "");
311  CheckFunctionName(script, "return 2", "");
312  CheckFunctionName(script, "return 3", "");
313}
314
315
316TEST(FactoryHashmap) {
317  InitializeVM();
318  v8::HandleScope scope;
319
320  v8::Handle<v8::Script> script = Compile(
321      "function createMyObj() {\n"
322      "  var obj = {};\n"
323      "  obj[\"method1\"] = function() { return 1; }\n"
324      "  obj[\"method2\"] = function() { return 2; }\n"
325      "  return obj;\n"
326      "}");
327  CheckFunctionName(script, "return 1", "obj.method1");
328  CheckFunctionName(script, "return 2", "obj.method2");
329}
330
331
332TEST(FactoryHashmapVariable) {
333  InitializeVM();
334  v8::HandleScope scope;
335
336  v8::Handle<v8::Script> script = Compile(
337      "function createMyObj() {\n"
338      "  var obj = {};\n"
339      "  var methodName = \"method1\";\n"
340      "  obj[methodName] = function() { return 1; }\n"
341      "  methodName = \"method2\";\n"
342      "  obj[methodName] = function() { return 2; }\n"
343      "  return obj;\n"
344      "}");
345  // Can't infer function names statically.
346  CheckFunctionName(script, "return 1", "obj.(anonymous function)");
347  CheckFunctionName(script, "return 2", "obj.(anonymous function)");
348}
349
350
351TEST(FactoryHashmapConditional) {
352  InitializeVM();
353  v8::HandleScope scope;
354
355  v8::Handle<v8::Script> script = Compile(
356      "function createMyObj() {\n"
357      "  var obj = {};\n"
358      "  obj[0 ? \"method1\" : \"method2\"] = function() { return 1; }\n"
359      "  return obj;\n"
360      "}");
361  // Can't infer the function name statically.
362  CheckFunctionName(script, "return 1", "obj.(anonymous function)");
363}
364
365
366TEST(GlobalAssignmentAndCall) {
367  InitializeVM();
368  v8::HandleScope scope;
369
370  v8::Handle<v8::Script> script = Compile(
371      "var Foo = function() {\n"
372      "  return 1;\n"
373      "}();\n"
374      "var Baz = Bar = function() {\n"
375      "  return 2;\n"
376      "}");
377  // The inferred name is empty, because this is an assignment of a result.
378  CheckFunctionName(script, "return 1", "");
379  // See MultipleAssignments test.
380  CheckFunctionName(script, "return 2", "Bar");
381}
382
383
384TEST(AssignmentAndCall) {
385  InitializeVM();
386  v8::HandleScope scope;
387
388  v8::Handle<v8::Script> script = Compile(
389      "(function Enclosing() {\n"
390      "  var Foo;\n"
391      "  Foo = function() {\n"
392      "    return 1;\n"
393      "  }();\n"
394      "  var Baz = Bar = function() {\n"
395      "    return 2;\n"
396      "  }\n"
397      "})();");
398  // The inferred name is empty, because this is an assignment of a result.
399  CheckFunctionName(script, "return 1", "");
400  // See MultipleAssignments test.
401  CheckFunctionName(script, "return 2", "Enclosing.Bar");
402}
403