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