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
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
50
CheckFunctionName(v8::Handle<v8::Script> script,const char * func_pos_src,const char * ref_inferred_name)51 static 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
Compile(v8::Isolate * isolate,const char * src)95 static v8::Handle<v8::Script> Compile(v8::Isolate* isolate, const char* src) {
96 return v8::Script::Compile(v8::String::NewFromUtf8(isolate, src));
97 }
98
99
TEST(GlobalProperty)100 TEST(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
TEST(GlobalVar)113 TEST(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
TEST(LocalVar)126 TEST(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
TEST(InConstructor)141 TEST(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
TEST(Factory)156 TEST(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
TEST(Static)173 TEST(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
TEST(Prototype)192 TEST(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
TEST(ObjectLiteral)211 TEST(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
TEST(AsParameter)226 TEST(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
TEST(MultipleFuncsConditional)243 TEST(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
TEST(MultipleFuncsInLiteral)257 TEST(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
TEST(AnonymousInAnonymousClosure1)272 TEST(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
TEST(AnonymousInAnonymousClosure2)292 TEST(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
TEST(NamedInAnonymousClosure)309 TEST(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
TEST(Issue380)327 TEST(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
TEST(MultipleAssignments)341 TEST(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
TEST(AsConstructorParameter)358 TEST(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
TEST(FactoryHashmap)373 TEST(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
TEST(FactoryHashmapVariable)390 TEST(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
TEST(FactoryHashmapConditional)410 TEST(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
TEST(GlobalAssignmentAndCall)426 TEST(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
TEST(AssignmentAndCall)445 TEST(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
TEST(MethodAssignmentInAnonymousFunctionCall)469 TEST(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
TEST(ReturnAnonymousFunction)486 TEST(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