Line data Source code
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 <memory>
29 :
30 : #include "src/v8.h"
31 :
32 : #include "src/api.h"
33 : #include "src/debug/debug.h"
34 : #include "src/objects-inl.h"
35 : #include "src/string-search.h"
36 : #include "test/cctest/cctest.h"
37 :
38 :
39 : using ::v8::internal::CStrVector;
40 : using ::v8::internal::Factory;
41 : using ::v8::internal::Handle;
42 : using ::v8::internal::Heap;
43 : using ::v8::internal::Isolate;
44 : using ::v8::internal::JSFunction;
45 : using ::v8::internal::Object;
46 : using ::v8::internal::Runtime;
47 : using ::v8::internal::Script;
48 : using ::v8::internal::SharedFunctionInfo;
49 : using ::v8::internal::String;
50 : using ::v8::internal::Vector;
51 :
52 :
53 306 : static void CheckFunctionName(v8::Local<v8::Script> script,
54 : const char* func_pos_src,
55 : const char* ref_inferred_name) {
56 306 : Isolate* isolate = CcTest::i_isolate();
57 :
58 : // Get script source.
59 : Handle<Object> obj = v8::Utils::OpenHandle(*script);
60 : Handle<SharedFunctionInfo> shared_function;
61 306 : if (obj->IsSharedFunctionInfo()) {
62 : shared_function =
63 : Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(*obj));
64 : } else {
65 : shared_function =
66 : Handle<SharedFunctionInfo>(JSFunction::cast(*obj)->shared());
67 : }
68 : Handle<Script> i_script(Script::cast(shared_function->script()));
69 306 : CHECK(i_script->source()->IsString());
70 : Handle<String> script_src(String::cast(i_script->source()));
71 :
72 : // Find the position of a given func source substring in the source.
73 : int func_pos;
74 : {
75 : i::DisallowHeapAllocation no_gc;
76 306 : Vector<const uint8_t> func_pos_str = i::OneByteVector(func_pos_src);
77 306 : String::FlatContent script_content = script_src->GetFlatContent();
78 : func_pos = SearchString(isolate, script_content.ToOneByteVector(),
79 612 : func_pos_str, 0);
80 : }
81 306 : CHECK_NE(0, func_pos);
82 :
83 : // Obtain SharedFunctionInfo for the function.
84 : Handle<SharedFunctionInfo> shared_func_info =
85 : Handle<SharedFunctionInfo>::cast(
86 306 : isolate->debug()->FindSharedFunctionInfoInScript(i_script, func_pos));
87 :
88 : // Verify inferred function name.
89 : std::unique_ptr<char[]> inferred_name =
90 306 : shared_func_info->inferred_name()->ToCString();
91 : i::PrintF("expected: %s, found: %s\n", ref_inferred_name,
92 306 : inferred_name.get());
93 306 : CHECK_EQ(0, strcmp(ref_inferred_name, inferred_name.get()));
94 306 : }
95 :
96 :
97 150 : static v8::Local<v8::Script> Compile(v8::Isolate* isolate, const char* src) {
98 : return v8::Script::Compile(
99 : isolate->GetCurrentContext(),
100 : v8::String::NewFromUtf8(isolate, src, v8::NewStringType::kNormal)
101 300 : .ToLocalChecked())
102 300 : .ToLocalChecked();
103 : }
104 :
105 :
106 23724 : TEST(GlobalProperty) {
107 6 : CcTest::InitializeVM();
108 6 : v8::HandleScope scope(CcTest::isolate());
109 :
110 : v8::Local<v8::Script> script = Compile(CcTest::isolate(),
111 : "fun1 = function() { return 1; }\n"
112 6 : "fun2 = function() { return 2; }\n");
113 6 : CheckFunctionName(script, "return 1", "fun1");
114 6 : CheckFunctionName(script, "return 2", "fun2");
115 6 : }
116 :
117 :
118 23724 : TEST(GlobalVar) {
119 6 : CcTest::InitializeVM();
120 6 : v8::HandleScope scope(CcTest::isolate());
121 :
122 : v8::Local<v8::Script> script =
123 : Compile(CcTest::isolate(),
124 : "var fun1 = function() { return 1; }\n"
125 6 : "var fun2 = function() { return 2; }\n");
126 6 : CheckFunctionName(script, "return 1", "fun1");
127 6 : CheckFunctionName(script, "return 2", "fun2");
128 6 : }
129 :
130 :
131 23724 : TEST(LocalVar) {
132 6 : CcTest::InitializeVM();
133 6 : v8::HandleScope scope(CcTest::isolate());
134 :
135 : v8::Local<v8::Script> script =
136 : Compile(CcTest::isolate(),
137 : "function outer() {\n"
138 : " var fun1 = function() { return 1; }\n"
139 : " var fun2 = function() { return 2; }\n"
140 6 : "}");
141 6 : CheckFunctionName(script, "return 1", "fun1");
142 6 : CheckFunctionName(script, "return 2", "fun2");
143 6 : }
144 :
145 23724 : TEST(ObjectProperty) {
146 6 : CcTest::InitializeVM();
147 6 : v8::HandleScope scope(CcTest::isolate());
148 :
149 : v8::Local<v8::Script> script =
150 : Compile(CcTest::isolate(),
151 : "var obj = {\n"
152 : " fun1: function() { return 1; },\n"
153 : " fun2: class { constructor() { return 2; } }\n"
154 6 : "}");
155 6 : CheckFunctionName(script, "return 1", "obj.fun1");
156 6 : CheckFunctionName(script, "return 2", "obj.fun2");
157 6 : }
158 :
159 23724 : TEST(InConstructor) {
160 6 : CcTest::InitializeVM();
161 6 : v8::HandleScope scope(CcTest::isolate());
162 :
163 : v8::Local<v8::Script> script =
164 : Compile(CcTest::isolate(),
165 : "function MyClass() {\n"
166 : " this.method1 = function() { return 1; }\n"
167 : " this.method2 = function() { return 2; }\n"
168 6 : "}");
169 6 : CheckFunctionName(script, "return 1", "MyClass.method1");
170 6 : CheckFunctionName(script, "return 2", "MyClass.method2");
171 6 : }
172 :
173 :
174 23724 : TEST(Factory) {
175 6 : CcTest::InitializeVM();
176 6 : v8::HandleScope scope(CcTest::isolate());
177 :
178 : v8::Local<v8::Script> script =
179 : Compile(CcTest::isolate(),
180 : "function createMyObj() {\n"
181 : " var obj = {};\n"
182 : " obj.method1 = function() { return 1; }\n"
183 : " obj.method2 = function() { return 2; }\n"
184 : " return obj;\n"
185 6 : "}");
186 6 : CheckFunctionName(script, "return 1", "obj.method1");
187 6 : CheckFunctionName(script, "return 2", "obj.method2");
188 6 : }
189 :
190 :
191 23724 : TEST(Static) {
192 6 : CcTest::InitializeVM();
193 6 : v8::HandleScope scope(CcTest::isolate());
194 :
195 : v8::Local<v8::Script> script =
196 : Compile(CcTest::isolate(),
197 : "function MyClass() {}\n"
198 : "MyClass.static1 = function() { return 1; }\n"
199 : "MyClass.static2 = function() { return 2; }\n"
200 : "MyClass.MyInnerClass = {}\n"
201 : "MyClass.MyInnerClass.static3 = function() { return 3; }\n"
202 6 : "MyClass.MyInnerClass.static4 = function() { return 4; }");
203 6 : CheckFunctionName(script, "return 1", "MyClass.static1");
204 6 : CheckFunctionName(script, "return 2", "MyClass.static2");
205 6 : CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.static3");
206 6 : CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.static4");
207 6 : }
208 :
209 :
210 23724 : TEST(Prototype) {
211 6 : CcTest::InitializeVM();
212 6 : v8::HandleScope scope(CcTest::isolate());
213 :
214 : v8::Local<v8::Script> script = Compile(
215 : CcTest::isolate(),
216 : "function MyClass() {}\n"
217 : "MyClass.prototype.method1 = function() { return 1; }\n"
218 : "MyClass.prototype.method2 = function() { return 2; }\n"
219 : "MyClass.MyInnerClass = function() {}\n"
220 : "MyClass.MyInnerClass.prototype.method3 = function() { return 3; }\n"
221 6 : "MyClass.MyInnerClass.prototype.method4 = function() { return 4; }");
222 6 : CheckFunctionName(script, "return 1", "MyClass.method1");
223 6 : CheckFunctionName(script, "return 2", "MyClass.method2");
224 6 : CheckFunctionName(script, "return 3", "MyClass.MyInnerClass.method3");
225 6 : CheckFunctionName(script, "return 4", "MyClass.MyInnerClass.method4");
226 6 : }
227 :
228 :
229 23724 : TEST(ObjectLiteral) {
230 6 : CcTest::InitializeVM();
231 6 : v8::HandleScope scope(CcTest::isolate());
232 :
233 : v8::Local<v8::Script> script =
234 : Compile(CcTest::isolate(),
235 : "function MyClass() {}\n"
236 : "MyClass.prototype = {\n"
237 : " method1: function() { return 1; },\n"
238 6 : " method2: function() { return 2; } }");
239 6 : CheckFunctionName(script, "return 1", "MyClass.method1");
240 6 : CheckFunctionName(script, "return 2", "MyClass.method2");
241 6 : }
242 :
243 :
244 23718 : TEST(UpperCaseClass) {
245 0 : CcTest::InitializeVM();
246 0 : v8::HandleScope scope(CcTest::isolate());
247 :
248 : v8::Local<v8::Script> script = Compile(CcTest::isolate(),
249 : "'use strict';\n"
250 : "class MyClass {\n"
251 : " constructor() {\n"
252 : " this.value = 1;\n"
253 : " }\n"
254 : " method() {\n"
255 : " this.value = 2;\n"
256 : " }\n"
257 0 : "}");
258 0 : CheckFunctionName(script, "this.value = 1", "MyClass");
259 0 : CheckFunctionName(script, "this.value = 2", "MyClass.method");
260 0 : }
261 :
262 :
263 23718 : TEST(LowerCaseClass) {
264 0 : CcTest::InitializeVM();
265 0 : v8::HandleScope scope(CcTest::isolate());
266 :
267 : v8::Local<v8::Script> script = Compile(CcTest::isolate(),
268 : "'use strict';\n"
269 : "class myclass {\n"
270 : " constructor() {\n"
271 : " this.value = 1;\n"
272 : " }\n"
273 : " method() {\n"
274 : " this.value = 2;\n"
275 : " }\n"
276 0 : "}");
277 0 : CheckFunctionName(script, "this.value = 1", "myclass");
278 0 : CheckFunctionName(script, "this.value = 2", "myclass.method");
279 0 : }
280 :
281 :
282 23724 : TEST(AsParameter) {
283 6 : CcTest::InitializeVM();
284 6 : v8::HandleScope scope(CcTest::isolate());
285 :
286 : v8::Local<v8::Script> script = Compile(
287 : CcTest::isolate(),
288 : "function f1(a) { return a(); }\n"
289 : "function f2(a, b) { return a() + b(); }\n"
290 : "var result1 = f1(function() { return 1; })\n"
291 6 : "var result2 = f2(function() { return 2; }, function() { return 3; })");
292 : // Can't infer names here.
293 6 : CheckFunctionName(script, "return 1", "");
294 6 : CheckFunctionName(script, "return 2", "");
295 6 : CheckFunctionName(script, "return 3", "");
296 6 : }
297 :
298 :
299 23724 : TEST(MultipleFuncsConditional) {
300 6 : CcTest::InitializeVM();
301 6 : v8::HandleScope scope(CcTest::isolate());
302 :
303 : v8::Local<v8::Script> script = Compile(CcTest::isolate(),
304 : "var x = 0;\n"
305 : "fun1 = x ?\n"
306 : " function() { return 1; } :\n"
307 6 : " function() { return 2; }");
308 6 : CheckFunctionName(script, "return 1", "fun1");
309 6 : CheckFunctionName(script, "return 2", "fun1");
310 6 : }
311 :
312 :
313 23724 : TEST(MultipleFuncsInLiteral) {
314 6 : CcTest::InitializeVM();
315 6 : v8::HandleScope scope(CcTest::isolate());
316 :
317 : v8::Local<v8::Script> script =
318 : Compile(CcTest::isolate(),
319 : "var x = 0;\n"
320 : "function MyClass() {}\n"
321 : "MyClass.prototype = {\n"
322 : " method1: x ? function() { return 1; } :\n"
323 6 : " function() { return 2; } }");
324 6 : CheckFunctionName(script, "return 1", "MyClass.method1");
325 6 : CheckFunctionName(script, "return 2", "MyClass.method1");
326 6 : }
327 :
328 :
329 23724 : TEST(AnonymousInAnonymousClosure1) {
330 6 : CcTest::InitializeVM();
331 6 : v8::HandleScope scope(CcTest::isolate());
332 :
333 : v8::Local<v8::Script> script = Compile(CcTest::isolate(),
334 : "(function() {\n"
335 : " (function() {\n"
336 : " var a = 1;\n"
337 : " return;\n"
338 : " })();\n"
339 : " var b = function() {\n"
340 : " var c = 1;\n"
341 : " return;\n"
342 : " };\n"
343 6 : "})();");
344 6 : CheckFunctionName(script, "return", "");
345 6 : }
346 :
347 :
348 23724 : TEST(AnonymousInAnonymousClosure2) {
349 6 : CcTest::InitializeVM();
350 6 : v8::HandleScope scope(CcTest::isolate());
351 :
352 : v8::Local<v8::Script> script = Compile(CcTest::isolate(),
353 : "(function() {\n"
354 : " (function() {\n"
355 : " var a = 1;\n"
356 : " return;\n"
357 : " })();\n"
358 : " var c = 1;\n"
359 6 : "})();");
360 6 : CheckFunctionName(script, "return", "");
361 6 : }
362 :
363 :
364 23724 : TEST(NamedInAnonymousClosure) {
365 6 : CcTest::InitializeVM();
366 6 : v8::HandleScope scope(CcTest::isolate());
367 :
368 : v8::Local<v8::Script> script = Compile(CcTest::isolate(),
369 : "var foo = function() {\n"
370 : " (function named() {\n"
371 : " var a = 1;\n"
372 : " })();\n"
373 : " var c = 1;\n"
374 : " return;\n"
375 6 : "};");
376 6 : CheckFunctionName(script, "return", "foo");
377 6 : }
378 :
379 :
380 : // See http://code.google.com/p/v8/issues/detail?id=380
381 23724 : TEST(Issue380) {
382 6 : CcTest::InitializeVM();
383 6 : v8::HandleScope scope(CcTest::isolate());
384 :
385 : v8::Local<v8::Script> script =
386 : Compile(CcTest::isolate(),
387 : "function a() {\n"
388 : "var result = function(p,a,c,k,e,d)"
389 : "{return p}(\"if blah blah\",62,1976,\'a|b\'.split(\'|\'),0,{})\n"
390 6 : "}");
391 6 : CheckFunctionName(script, "return p", "");
392 6 : }
393 :
394 :
395 23724 : TEST(MultipleAssignments) {
396 6 : CcTest::InitializeVM();
397 6 : v8::HandleScope scope(CcTest::isolate());
398 :
399 : v8::Local<v8::Script> script =
400 : Compile(CcTest::isolate(),
401 : "var fun1 = fun2 = function () { return 1; }\n"
402 : "var bar1 = bar2 = bar3 = function () { return 2; }\n"
403 : "foo1 = foo2 = function () { return 3; }\n"
404 6 : "baz1 = baz2 = baz3 = function () { return 4; }");
405 6 : CheckFunctionName(script, "return 1", "fun2");
406 6 : CheckFunctionName(script, "return 2", "bar3");
407 6 : CheckFunctionName(script, "return 3", "foo2");
408 6 : CheckFunctionName(script, "return 4", "baz3");
409 6 : }
410 :
411 :
412 23724 : TEST(AsConstructorParameter) {
413 6 : CcTest::InitializeVM();
414 6 : v8::HandleScope scope(CcTest::isolate());
415 :
416 : v8::Local<v8::Script> script = Compile(
417 : CcTest::isolate(),
418 : "function Foo() {}\n"
419 : "var foo = new Foo(function() { return 1; })\n"
420 6 : "var bar = new Foo(function() { return 2; }, function() { return 3; })");
421 6 : CheckFunctionName(script, "return 1", "");
422 6 : CheckFunctionName(script, "return 2", "");
423 6 : CheckFunctionName(script, "return 3", "");
424 6 : }
425 :
426 :
427 23724 : TEST(FactoryHashmap) {
428 6 : CcTest::InitializeVM();
429 6 : v8::HandleScope scope(CcTest::isolate());
430 :
431 : v8::Local<v8::Script> script =
432 : Compile(CcTest::isolate(),
433 : "function createMyObj() {\n"
434 : " var obj = {};\n"
435 : " obj[\"method1\"] = function() { return 1; }\n"
436 : " obj[\"method2\"] = function() { return 2; }\n"
437 : " return obj;\n"
438 6 : "}");
439 6 : CheckFunctionName(script, "return 1", "obj.method1");
440 6 : CheckFunctionName(script, "return 2", "obj.method2");
441 6 : }
442 :
443 :
444 23724 : TEST(FactoryHashmapVariable) {
445 6 : CcTest::InitializeVM();
446 6 : v8::HandleScope scope(CcTest::isolate());
447 :
448 : v8::Local<v8::Script> script =
449 : Compile(CcTest::isolate(),
450 : "function createMyObj() {\n"
451 : " var obj = {};\n"
452 : " var methodName = \"method1\";\n"
453 : " obj[methodName] = function() { return 1; }\n"
454 : " methodName = \"method2\";\n"
455 : " obj[methodName] = function() { return 2; }\n"
456 : " return obj;\n"
457 6 : "}");
458 : // Can't infer function names statically.
459 6 : CheckFunctionName(script, "return 1", "obj.(anonymous function)");
460 6 : CheckFunctionName(script, "return 2", "obj.(anonymous function)");
461 6 : }
462 :
463 :
464 23724 : TEST(FactoryHashmapConditional) {
465 6 : CcTest::InitializeVM();
466 6 : v8::HandleScope scope(CcTest::isolate());
467 :
468 : v8::Local<v8::Script> script = Compile(
469 : CcTest::isolate(),
470 : "function createMyObj() {\n"
471 : " var obj = {};\n"
472 : " obj[0 ? \"method1\" : \"method2\"] = function() { return 1; }\n"
473 : " return obj;\n"
474 6 : "}");
475 : // Can't infer the function name statically.
476 6 : CheckFunctionName(script, "return 1", "obj.(anonymous function)");
477 6 : }
478 :
479 :
480 23724 : TEST(GlobalAssignmentAndCall) {
481 6 : CcTest::InitializeVM();
482 6 : v8::HandleScope scope(CcTest::isolate());
483 :
484 : v8::Local<v8::Script> script = Compile(CcTest::isolate(),
485 : "var Foo = function() {\n"
486 : " return 1;\n"
487 : "}();\n"
488 : "var Baz = Bar = function() {\n"
489 : " return 2;\n"
490 6 : "}");
491 : // The inferred name is empty, because this is an assignment of a result.
492 6 : CheckFunctionName(script, "return 1", "");
493 : // See MultipleAssignments test.
494 6 : CheckFunctionName(script, "return 2", "Bar");
495 6 : }
496 :
497 :
498 23724 : TEST(AssignmentAndCall) {
499 6 : CcTest::InitializeVM();
500 6 : v8::HandleScope scope(CcTest::isolate());
501 :
502 : v8::Local<v8::Script> script = Compile(CcTest::isolate(),
503 : "(function Enclosing() {\n"
504 : " var Foo;\n"
505 : " Foo = function() {\n"
506 : " return 1;\n"
507 : " }();\n"
508 : " var Baz = Bar = function() {\n"
509 : " return 2;\n"
510 : " }\n"
511 6 : "})();");
512 : // The inferred name is empty, because this is an assignment of a result.
513 6 : CheckFunctionName(script, "return 1", "");
514 : // See MultipleAssignments test.
515 : // TODO(2276): Lazy compiling the enclosing outer closure would yield
516 : // in "Enclosing.Bar" being the inferred name here.
517 6 : CheckFunctionName(script, "return 2", "Bar");
518 6 : }
519 :
520 :
521 23724 : TEST(MethodAssignmentInAnonymousFunctionCall) {
522 6 : CcTest::InitializeVM();
523 6 : v8::HandleScope scope(CcTest::isolate());
524 :
525 : v8::Local<v8::Script> script =
526 : Compile(CcTest::isolate(),
527 : "(function () {\n"
528 : " var EventSource = function () { };\n"
529 : " EventSource.prototype.addListener = function () {\n"
530 : " return 2012;\n"
531 : " };\n"
532 : " this.PublicEventSource = EventSource;\n"
533 6 : "})();");
534 6 : CheckFunctionName(script, "return 2012", "EventSource.addListener");
535 6 : }
536 :
537 :
538 23724 : TEST(ReturnAnonymousFunction) {
539 6 : CcTest::InitializeVM();
540 6 : v8::HandleScope scope(CcTest::isolate());
541 :
542 : v8::Local<v8::Script> script = Compile(CcTest::isolate(),
543 : "(function() {\n"
544 : " function wrapCode() {\n"
545 : " return function () {\n"
546 : " return 2012;\n"
547 : " };\n"
548 : " };\n"
549 : " var foo = 10;\n"
550 : " function f() {\n"
551 : " return wrapCode();\n"
552 : " }\n"
553 : " this.ref = f;\n"
554 6 : "})()");
555 12 : script->Run(CcTest::isolate()->GetCurrentContext()).ToLocalChecked();
556 6 : CheckFunctionName(script, "return 2012", "");
557 71160 : }
|