Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
isolate_reload_test.cc
Go to the documentation of this file.
1// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include <array>
6
7#include "include/dart_api.h"
9#include "platform/assert.h"
11#include "vm/globals.h"
12#include "vm/isolate.h"
13#include "vm/kernel_loader.h"
14#include "vm/lockers.h"
15#include "vm/thread_barrier.h"
16#include "vm/thread_pool.h"
17#include "vm/unit_test.h"
18
19namespace dart {
20
21#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
22
23int64_t SimpleInvoke(Dart_Handle lib, const char* method) {
24 Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, nullptr);
27 int64_t integer_result = 0;
28 result = Dart_IntegerToInt64(result, &integer_result);
30 return integer_result;
31}
32
33const char* SimpleInvokeStr(Dart_Handle lib, const char* method) {
34 Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, nullptr);
35 const char* result_str = nullptr;
38 return result_str;
39}
40
41Dart_Handle SimpleInvokeError(Dart_Handle lib, const char* method) {
42 Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, nullptr);
44 return result;
45}
46
47TEST_CASE(IsolateReload_FunctionReplacement) {
48 const char* kScript =
49 "main() {\n"
50 " return 4;\n"
51 "}\n";
52
53 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
54 EXPECT_VALID(lib);
55
56 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
57
58 const char* kReloadScript =
59 "var _unused;"
60 "main() {\n"
61 " return 10;\n"
62 "}\n";
63
64 lib = TestCase::ReloadTestScript(kReloadScript);
65 EXPECT_VALID(lib);
66 EXPECT_EQ(10, SimpleInvoke(lib, "main"));
67}
68
69TEST_CASE(IsolateReload_IncrementalCompile) {
70 const char* kScriptChars =
71 "main() {\n"
72 " return 42;\n"
73 "}\n";
74 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
75 EXPECT_VALID(lib);
76 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
77 int64_t value = 0;
80 EXPECT_EQ(42, value);
81
82 const char* kUpdatedScriptChars =
83 "main() {\n"
84 " return 24;\n"
85 "}\n"
86 "";
87 lib = TestCase::ReloadTestScript(kUpdatedScriptChars);
88 EXPECT_VALID(lib);
89 result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
92 EXPECT_EQ(24, value);
93}
94
95TEST_CASE(IsolateReload_KernelIncrementalCompile) {
96 // clang-format off
97 Dart_SourceFile sourcefiles[] = {
98 {
99 "file:///test-app",
100 "main() {\n"
101 " return 42;\n"
102 "}\n",
103 }};
104 // clang-format on
105
107 sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
108 nullptr /* resolver */, true /* finalize */, true /* incrementally */);
109 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
110 int64_t value = 0;
113 EXPECT_EQ(42, value);
114
115 // clang-format off
116 Dart_SourceFile updated_sourcefiles[] = {
117 {
118 "file:///test-app",
119 "main() {\n"
120 " return 24;\n"
121 "}\n"
122 ""
123 }};
124 // clang-format on
125 {
126 const uint8_t* kernel_buffer = nullptr;
127 intptr_t kernel_buffer_size = 0;
129 "file:///test-app",
130 sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
131 updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
132 true /* incrementally */);
133 EXPECT(error == nullptr);
134 EXPECT_NOTNULL(kernel_buffer);
135
136 lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
137 EXPECT_VALID(lib);
138 }
139 result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
142 EXPECT_EQ(24, value);
143}
144
145TEST_CASE(IsolateReload_KernelIncrementalCompileAppAndLib) {
146 // clang-format off
147 Dart_SourceFile sourcefiles[] = {
148 {
149 "file:///test-app.dart",
150 "import 'test-lib.dart';\n"
151 "main() {\n"
152 " return WhatsTheMeaningOfAllThis();\n"
153 "}\n",
154 },
155 {
156 "file:///test-lib.dart",
157 "WhatsTheMeaningOfAllThis() {\n"
158 " return 42;\n"
159 "}\n",
160 }};
161 // clang-format on
162
164 sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
165 nullptr /* resolver */, true /* finalize */, true /* incrementally */);
166 EXPECT_VALID(lib);
167 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
168 int64_t value = 0;
171 EXPECT_EQ(42, value);
172
173 // clang-format off
174 Dart_SourceFile updated_sourcefiles[] = {
175 {
176 "file:///test-lib.dart",
177 "WhatsTheMeaningOfAllThis() {\n"
178 " return 24;\n"
179 "}\n"
180 ""
181 }};
182 // clang-format on
183
184 {
185 const uint8_t* kernel_buffer = nullptr;
186 intptr_t kernel_buffer_size = 0;
188 "file:///test-app.dart",
189 sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
190 updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
191 true /* incrementally */);
192 EXPECT(error == nullptr);
193 EXPECT_NOTNULL(kernel_buffer);
194
195 lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
196 EXPECT_VALID(lib);
197 }
198 result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
201 EXPECT_EQ(24, value);
202}
203
204TEST_CASE(IsolateReload_KernelIncrementalCompileGenerics) {
205 // clang-format off
206 Dart_SourceFile sourcefiles[] = {
207 {
208 "file:///test-app.dart",
209 "import 'test-lib.dart';\n"
210 "class Account {\n"
211 " int balance() => 42;\n"
212 "}\n"
213 "class MyAccountState extends State<Account> {\n"
214 " MyAccountState(Account a): super(a) {}\n"
215 "}\n"
216 "main() {\n"
217 " return (new MyAccountState(new Account()))\n"
218 " .howAreTheThings().balance();\n"
219 "}\n",
220 },
221 {
222 "file:///test-lib.dart",
223 "class State<T> {\n"
224 " T t;"
225 " State(this.t);\n"
226 " T howAreTheThings() => t;\n"
227 "}\n",
228 }};
229 // clang-format on
230
232 sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
233 nullptr /* resolver */, true /* finalize */, true /* incrementally */);
234 EXPECT_VALID(lib);
235 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
236 int64_t value = 0;
239 EXPECT_EQ(42, value);
240
241 // clang-format off
242 Dart_SourceFile updated_sourcefiles[] = {
243 {
244 "file:///test-app.dart",
245 "import 'test-lib.dart';\n"
246 "class Account {\n"
247 " int balance() => 24;\n"
248 "}\n"
249 "class MyAccountState extends State<Account> {\n"
250 " MyAccountState(Account a): super(a) {}\n"
251 "}\n"
252 "main() {\n"
253 " return (new MyAccountState(new Account()))\n"
254 " .howAreTheThings().balance();\n"
255 "}\n",
256 }};
257 // clang-format on
258 {
259 const uint8_t* kernel_buffer = nullptr;
260 intptr_t kernel_buffer_size = 0;
262 "file:///test-app.dart",
263 sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
264 updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
265 true /* incrementally */);
266 EXPECT(error == nullptr);
267 EXPECT_NOTNULL(kernel_buffer);
268
269 lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
270 EXPECT_VALID(lib);
271 }
272 result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
275 EXPECT_EQ(24, value);
276}
277
278TEST_CASE(IsolateReload_KernelIncrementalCompileBaseClass) {
279 const char* nullable_tag = TestCase::NullableTag();
280 // clang-format off
281 auto kSourceFile1 =
283 "class State<T, U> {\n"
284 " T%s t;\n"
285 " U%s u;\n"
286 " State(List l) {\n"
287 " t = l[0] is T ? l[0] : null;\n"
288 " u = l[1] is U ? l[1] : null;\n"
289 " }\n"
290 "}\n",
291 nullable_tag, nullable_tag),
292 std::free);
293 Dart_SourceFile sourcefiles[3] = {
294 {
295 "file:///test-app.dart",
296 "import 'test-util.dart';\n"
297 "main() {\n"
298 " var v = doWork();"
299 " return v == 42 ? 1 : v == null ? -1 : 0;\n"
300 "}\n",
301 },
302 {
303 "file:///test-lib.dart",
304 kSourceFile1.get()
305 },
306 {
307 "file:///test-util.dart",
308 "import 'test-lib.dart';\n"
309 "class MyAccountState extends State<int, String> {\n"
310 " MyAccountState(List l): super(l) {}\n"
311 " first() => t;\n"
312 "}\n"
313 "doWork() => new MyAccountState(<dynamic>[42, 'abc']).first();\n"
314 }
315 };
316 // clang-format on
317
319 sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
320 nullptr /* resolver */, true /* finalize */, true /* incrementally */);
321 EXPECT_VALID(lib);
322 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
323 int64_t value = 0;
326 EXPECT_EQ(1, value);
327
328 auto kUpdatedSourceFile =
330 "class State<U, T> {\n"
331 " T%s t;\n"
332 " U%s u;\n"
333 " State(List l) {\n"
334 " t = l[0] is T ? l[0] : null;\n"
335 " u = l[1] is U ? l[1] : null;\n"
336 " }\n"
337 "}\n",
338 nullable_tag, nullable_tag),
339 std::free);
340 Dart_SourceFile updated_sourcefiles[1] = {{
341 "file:///test-lib.dart",
342 kUpdatedSourceFile.get(),
343 }};
344 {
345 const uint8_t* kernel_buffer = nullptr;
346 intptr_t kernel_buffer_size = 0;
348 "file:///test-app.dart",
349 sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
350 updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
351 true /* incrementally */);
352 EXPECT(error == nullptr);
353 EXPECT_NOTNULL(kernel_buffer);
354
355 lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
356 EXPECT_VALID(lib);
357 }
358 result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
361 EXPECT_EQ(-1, value);
362}
363
364TEST_CASE(IsolateReload_BadClass) {
365 const char* kScript =
366 "class Foo {\n"
367 " final a;\n"
368 " Foo(this.a);\n"
369 "}\n"
370 "main() {\n"
371 " new Foo(5);\n"
372 " return 4;\n"
373 "}\n";
374
375 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
376 EXPECT_VALID(lib);
377 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
378
379 const char* kReloadScript =
380 "var _unused;"
381 "class Foo {\n"
382 " final a kjsdf ksjdf ;\n"
383 " Foo(this.a);\n"
384 "}\n"
385 "main() {\n"
386 " new Foo(5);\n"
387 " return 10;\n"
388 "}\n";
389
391 EXPECT_ERROR(result, "Expected ';' after this");
392 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
393}
394
395TEST_CASE(IsolateReload_StaticValuePreserved) {
396 const char* kScript =
397 "init() => 'old value';\n"
398 "var value = init();\n"
399 "main() {\n"
400 " return 'init()=${init()},value=${value}';\n"
401 "}\n";
402
403 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
404 EXPECT_VALID(lib);
405 EXPECT_STREQ("init()=old value,value=old value",
406 SimpleInvokeStr(lib, "main"));
407
408 const char* kReloadScript =
409 "var _unused;"
410 "init() => 'new value';\n"
411 "var value = init();\n"
412 "main() {\n"
413 " return 'init()=${init()},value=${value}';\n"
414 "}\n";
415
416 lib = TestCase::ReloadTestScript(kReloadScript);
417 EXPECT_VALID(lib);
418 EXPECT_STREQ("init()=new value,value=old value",
419 SimpleInvokeStr(lib, "main"));
420}
421
422TEST_CASE(IsolateReload_SavedClosure) {
423 // Create a closure in main which only exists in the original source.
424 const char* kScript =
425 "magic() {\n"
426 " var x = 'ante';\n"
427 " return x + 'diluvian';\n"
428 "}\n"
429 "var closure;\n"
430 "main() {\n"
431 " closure = () { return magic().toString() + '!'; };\n"
432 " return closure();\n"
433 "}\n";
434
435 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
436 EXPECT_VALID(lib);
437 EXPECT_STREQ("antediluvian!", SimpleInvokeStr(lib, "main"));
438
439 // Remove the original closure from the source code. The closure is
440 // able to be recompiled because its source is preserved in a
441 // special patch class.
442 const char* kReloadScript =
443 "magic() {\n"
444 " return 'postapocalyptic';\n"
445 "}\n"
446 "var closure;\n"
447 "main() {\n"
448 " return closure();\n"
449 "}\n";
450
451 lib = TestCase::ReloadTestScript(kReloadScript);
452 EXPECT_VALID(lib);
453 EXPECT_STREQ("postapocalyptic!", SimpleInvokeStr(lib, "main"));
454}
455
456TEST_CASE(IsolateReload_TopLevelFieldAdded) {
457 const char* kScript =
458 "var value1 = 10;\n"
459 "main() {\n"
460 " return 'value1=${value1}';\n"
461 "}\n";
462
463 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
464 EXPECT_VALID(lib);
465 EXPECT_STREQ("value1=10", SimpleInvokeStr(lib, "main"));
466
467 const char* kReloadScript =
468 "var value1 = 10;\n"
469 "var value2 = 20;\n"
470 "main() {\n"
471 " return 'value1=${value1},value2=${value2}';\n"
472 "}\n";
473
474 lib = TestCase::ReloadTestScript(kReloadScript);
475 EXPECT_VALID(lib);
476 EXPECT_STREQ("value1=10,value2=20", SimpleInvokeStr(lib, "main"));
477}
478
479TEST_CASE(IsolateReload_ClassFieldAdded) {
480 const char* kScript =
481 "class Foo {\n"
482 " var x;\n"
483 "}\n"
484 "main() {\n"
485 " new Foo();\n"
486 " return 44;\n"
487 "}\n";
488
489 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
490 EXPECT_VALID(lib);
491 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
492
493 const char* kReloadScript =
494 "class Foo {\n"
495 " var x;\n"
496 " var y;\n"
497 "}\n"
498 "main() {\n"
499 " new Foo();\n"
500 " return 44;\n"
501 "}\n";
502
503 lib = TestCase::ReloadTestScript(kReloadScript);
504 EXPECT_VALID(lib);
505 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
506}
507
508TEST_CASE(IsolateReload_ClassFieldAdded2) {
509 const char* kScript =
510 "class Foo {\n"
511 " var x;\n"
512 " var y;\n"
513 "}\n"
514 "main() {\n"
515 " new Foo();\n"
516 " return 44;\n"
517 "}\n";
518
519 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
520 EXPECT_VALID(lib);
521 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
522
523 const char* kReloadScript =
524 "class Foo {\n"
525 " var x;\n"
526 " var y;\n"
527 " var z;\n"
528 "}\n"
529 "main() {\n"
530 " new Foo();\n"
531 " return 44;\n"
532 "}\n";
533
534 lib = TestCase::ReloadTestScript(kReloadScript);
535 EXPECT_VALID(lib);
536 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
537}
538
539TEST_CASE(IsolateReload_ClassFieldRemoved) {
540 const char* kScript =
541 "class Foo {\n"
542 " var x;\n"
543 " var y;\n"
544 "}\n"
545 "main() {\n"
546 " new Foo();\n"
547 " return 44;\n"
548 "}\n";
549
550 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
551 EXPECT_VALID(lib);
552 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
553
554 const char* kReloadScript =
555 "class Foo {\n"
556 " var x;\n"
557 "}\n"
558 "main() {\n"
559 " new Foo();\n"
560 " return 44;\n"
561 "}\n";
562
563 lib = TestCase::ReloadTestScript(kReloadScript);
564 EXPECT_VALID(lib);
565 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
566}
567
568TEST_CASE(IsolateReload_ClassAdded) {
569 const char* kScript =
570 "main() {\n"
571 " return 'hello';\n"
572 "}\n";
573
574 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
575 EXPECT_VALID(lib);
576 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
577
578 const char* kReloadScript =
579 "var _unused;"
580 "class A {\n"
581 " toString() => 'hello from A';\n"
582 "}\n"
583 "main() {\n"
584 " return new A().toString();\n"
585 "}\n";
586
587 lib = TestCase::ReloadTestScript(kReloadScript);
588 EXPECT_VALID(lib);
589 EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
590}
591
592TEST_CASE(IsolateReload_ClassRemoved) {
593 const char* kScript =
594 "class A {\n"
595 " toString() => 'hello from A';\n"
596 "}\n"
597 "List<dynamic> list = <dynamic>[];"
598 "main() {\n"
599 " list.add(new A());\n"
600 " return list[0].toString();\n"
601 "}\n";
602
603 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
604 EXPECT_VALID(lib);
605 EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
606
607 const char* kReloadScript =
608 "List<dynamic> list = <dynamic>[];\n"
609 "main() {\n"
610 " return list[0].toString();\n"
611 "}\n";
612
613 lib = TestCase::ReloadTestScript(kReloadScript);
614 EXPECT_VALID(lib);
615 EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
616}
617
618TEST_CASE(IsolateReload_LibraryImportAdded) {
619 const char* kScript =
620 "main() {\n"
621 " return max(3, 4);\n"
622 "}\n";
623
624 const char* kReloadScript =
625 "import 'dart:math';\n"
626 "main() {\n"
627 " return max(3, 4);\n"
628 "}\n";
629
631 EXPECT_VALID(lib);
632 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");
633
634 lib = TestCase::ReloadTestScript(kReloadScript);
635 EXPECT_VALID(lib);
636 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
637}
638
639TEST_CASE(IsolateReload_LibraryImportRemoved) {
640 const char* kScript =
641 "import 'dart:math';\n"
642 "main() {\n"
643 " return max(3, 4);\n"
644 "}\n";
645
646 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
647 EXPECT_VALID(lib);
648 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
649
650 const char* kReloadScript =
651 "main() {\n"
652 " return max(3, 4);\n"
653 "}\n";
654
655 lib = TestCase::ReloadTestScript(kReloadScript);
656 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");
657}
658
659TEST_CASE(IsolateReload_LibraryDebuggable) {
660 const char* kScript =
661 "main() {\n"
662 " return 1;\n"
663 "}\n";
664
665 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
666 EXPECT_VALID(lib);
667
668 // The library is by default debuggable. Make it not debuggable.
669 intptr_t lib_id = -1;
670 bool debuggable = false;
671 EXPECT_VALID(Dart_LibraryId(lib, &lib_id));
672 EXPECT_VALID(Dart_GetLibraryDebuggable(lib_id, &debuggable));
673 EXPECT_EQ(true, debuggable);
675 EXPECT_VALID(Dart_GetLibraryDebuggable(lib_id, &debuggable));
676 EXPECT_EQ(false, debuggable);
677
678 EXPECT_EQ(1, SimpleInvoke(lib, "main"));
679
680 const char* kReloadScript =
681 "main() {\n"
682 " return 2;\n"
683 "}\n";
684
685 lib = TestCase::ReloadTestScript(kReloadScript);
686 EXPECT_VALID(lib);
687
688 EXPECT_EQ(2, SimpleInvoke(lib, "main"));
689
690 // Library debuggability is preserved.
691 intptr_t new_lib_id = -1;
692 EXPECT_VALID(Dart_LibraryId(lib, &new_lib_id));
693 EXPECT_VALID(Dart_GetLibraryDebuggable(new_lib_id, &debuggable));
694 EXPECT_EQ(false, debuggable);
695}
696
697TEST_CASE(IsolateReload_ImplicitConstructorChanged) {
698 // Note that we are checking that the value 20 gets cleared from the
699 // compile-time constants cache. To make this test work, "20" and
700 // "10" need to be at the same token position.
701 const char* kScript =
702 "class A {\n"
703 " int field = 20;\n"
704 "}\n"
705 "var savedA = new A();\n"
706 "main() {\n"
707 " var newA = new A();\n"
708 " return 'saved:${savedA.field} new:${newA.field}';\n"
709 "}\n";
710
711 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
712 EXPECT_VALID(lib);
713 EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
714
715 const char* kReloadScript =
716 "class A {\n"
717 " int field = 10;\n"
718 "}\n"
719 "var savedA = new A();\n"
720 "main() {\n"
721 " var newA = new A();\n"
722 " return 'saved:${savedA.field} new:${newA.field}';\n"
723 "}\n";
724
725 lib = TestCase::ReloadTestScript(kReloadScript);
726 EXPECT_VALID(lib);
727 EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
728}
729
730TEST_CASE(IsolateReload_ConstructorChanged) {
731 const char* late_tag = TestCase::LateTag();
732 // clang-format off
733 auto kScript = Utils::CStringUniquePtr(
734 OS::SCreate(nullptr,
735 "class A {\n"
736 " %s int field;\n"
737 " A() { field = 20; }\n"
738 "}\n"
739 "var savedA = A();\n"
740 "main() {\n"
741 " var newA = A();\n"
742 " return 'saved:${savedA.field} new:${newA.field}';\n"
743 "}\n",
744 late_tag),
745 std::free);
746 // clang-format on
747
748 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
749 EXPECT_VALID(lib);
750 EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
751
752 // clang-format off
753 auto kReloadScript = Utils::CStringUniquePtr(
754 OS::SCreate(nullptr,
755 "var _unused;"
756 "class A {\n"
757 " %s int field;\n"
758 " A() { field = 10; }\n"
759 "}\n"
760 "var savedA = A();\n"
761 "main() {\n"
762 " var newA = A();\n"
763 " return 'saved:${savedA.field} new:${newA.field}';\n"
764 "}\n",
765 late_tag),
766 std::free);
767 // clang-format on
768
769 lib = TestCase::ReloadTestScript(kReloadScript.get());
770 EXPECT_VALID(lib);
771 EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
772}
773
774TEST_CASE(IsolateReload_SuperClassChanged) {
775 const char* kScript =
776 "class A {\n"
777 "}\n"
778 "class B extends A {\n"
779 "}\n"
780 "var list = [ new A(), new B() ];\n"
781 "main() {\n"
782 " return (list.map((x) => '${x is A}/${x is B}')).toString();\n"
783 "}\n";
784
785 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
786 EXPECT_VALID(lib);
787 EXPECT_STREQ("(true/false, true/true)", SimpleInvokeStr(lib, "main"));
788
789 const char* kReloadScript =
790 "var _unused;"
791 "class B{\n"
792 "}\n"
793 "class A extends B {\n"
794 "}\n"
795 "var list = [ new A(), new B() ];\n"
796 "main() {\n"
797 " return (list.map((x) => '${x is A}/${x is B}')).toString();\n"
798 "}\n";
799
800 lib = TestCase::ReloadTestScript(kReloadScript);
801 EXPECT_VALID(lib);
802 EXPECT_STREQ("(true/true, false/true)", SimpleInvokeStr(lib, "main"));
803}
804
805TEST_CASE(IsolateReload_Generics) {
806 // Reload a program with generics without changing the source. We
807 // do this to produce duplication TypeArguments and make sure that
808 // the system doesn't die.
809 const char* kScript =
810 "class A {\n"
811 "}\n"
812 "class B<T extends A> {\n"
813 "}\n"
814 "main() {\n"
815 " return new B<A>().toString();\n"
816 "}\n";
817
818 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
819 EXPECT_VALID(lib);
820 EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
821
822 const char* kReloadScript =
823 "class A {\n"
824 "}\n"
825 "class B<T extends A> {\n"
826 "}\n"
827 "main() {\n"
828 " return new B<A>().toString();\n"
829 "}\n";
830
831 lib = TestCase::ReloadTestScript(kReloadScript);
832 EXPECT_VALID(lib);
833 EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
834}
835
836TEST_CASE(IsolateReload_TypeIdentity) {
837 const char* kScript =
838 "import 'file:///test:isolate_reload_helper';\n"
839 "class T { }\n"
840 "getType() => T;\n"
841 "main() {\n"
842 " var oldType = getType();\n"
843 " reloadTest();\n"
844 " var newType = getType();\n"
845 " return identical(oldType, newType).toString();\n"
846 "}\n";
847
848 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
849 EXPECT_VALID(lib);
850
851 const char* kReloadScript =
852 "import 'file:///test:isolate_reload_helper';\n"
853 "class T extends Stopwatch { }\n"
854 "getType() => T;\n"
855 "main() {\n"
856 " var oldType = getType();\n"
857 " reloadTest();\n"
858 " var newType = getType();\n"
859 " return identical(oldType, newType).toString();\n"
860 "}\n";
861
863
864 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
865}
866
867TEST_CASE(IsolateReload_TypeIdentityGeneric) {
868 const char* kScript =
869 "import 'file:///test:isolate_reload_helper';\n"
870 "class T<G> { }\n"
871 "getType() => new T<int>().runtimeType;\n"
872 "main() {\n"
873 " var oldType = getType();\n"
874 " reloadTest();\n"
875 " var newType = getType();\n"
876 " return identical(oldType, newType).toString();\n"
877 "}\n";
878
879 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
880 EXPECT_VALID(lib);
881
882 const char* kReloadScript =
883 "import 'file:///test:isolate_reload_helper';\n"
884 "class T<G> extends Stopwatch { }\n"
885 "getType() => new T<int>().runtimeType;\n"
886 "main() {\n"
887 " var oldType = getType();\n"
888 " reloadTest();\n"
889 " var newType = getType();\n"
890 " return identical(oldType, newType).toString();\n"
891 "}\n";
892
894
895 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
896}
897
898TEST_CASE(IsolateReload_TypeIdentityParameter) {
899 const char* kScript =
900 "import 'dart:mirrors';\n"
901 "import 'file:///test:isolate_reload_helper';\n"
902 "class T<G> { }\n"
903 "getTypeVar() => reflectType(T).typeVariables[0];\n"
904 "main() {\n"
905 " var oldType = getTypeVar();\n"
906 " reloadTest();\n"
907 " var newType = getTypeVar();\n"
908 " return (oldType == newType).toString();\n"
909 "}\n";
910
911 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
912 EXPECT_VALID(lib);
913
914 const char* kReloadScript =
915 "import 'dart:mirrors';\n"
916 "import 'file:///test:isolate_reload_helper';\n"
917 "class T<G> extends Stopwatch { }\n"
918 "getTypeVar() => reflectType(T).typeVariables[0];\n"
919 "main() {\n"
920 " var oldType = getTypeVar();\n"
921 " reloadTest();\n"
922 " var newType = getTypeVar();\n"
923 " return (oldType == newType).toString();\n"
924 "}\n";
925
927
928 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
929}
930
931TEST_CASE(IsolateReload_MixinChanged) {
932 const char* kScript =
933 "mixin Mixin1 {\n"
934 " var field = 'mixin1';\n"
935 " func() => 'mixin1';\n"
936 "}\n"
937 "class B extends Object with Mixin1 {\n"
938 "}\n"
939 "var saved = new B();\n"
940 "main() {\n"
941 " return 'saved:field=${saved.field},func=${saved.func()}';\n"
942 "}\n";
943
944 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
945 EXPECT_VALID(lib);
946 EXPECT_STREQ("saved:field=mixin1,func=mixin1", SimpleInvokeStr(lib, "main"));
947
948 const char* kReloadScript =
949 "mixin Mixin2 {\n"
950 " var field = 'mixin2';\n"
951 " func() => 'mixin2';\n"
952 "}\n"
953 "class B extends Object with Mixin2 {\n"
954 "}\n"
955 "var saved = new B();\n"
956 "main() {\n"
957 " var newer = new B();\n"
958 " return 'saved:field=${saved.field},func=${saved.func()} '\n"
959 " 'newer:field=${newer.field},func=${newer.func()}';\n"
960 "}\n";
961
962 lib = TestCase::ReloadTestScript(kReloadScript);
963 EXPECT_VALID(lib);
964
965 // The saved instance of B retains its old field value from mixin1,
966 // but it gets the new implementation of func from mixin2.
967 EXPECT_STREQ(
968 "saved:field=mixin1,func=mixin2 "
969 "newer:field=mixin2,func=mixin2",
970 SimpleInvokeStr(lib, "main"));
971}
972
973TEST_CASE(IsolateReload_ComplexInheritanceChange) {
974 const char* kScript =
975 "class A {\n"
976 " String name;\n"
977 " A(this.name);\n"
978 "}\n"
979 "class B extends A {\n"
980 " B(name) : super(name);\n"
981 "}\n"
982 "class C extends B {\n"
983 " C(name) : super(name);\n"
984 "}\n"
985 "var list = <dynamic>[ new A('a'), new B('b'), new C('c') ];\n"
986 "main() {\n"
987 " return (list.map((x) {\n"
988 " return '${x.name} is A(${x is A})/ B(${x is B})/ C(${x is C})';\n"
989 " })).toString();\n"
990 "}\n";
991
992 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
993 EXPECT_VALID(lib);
994 EXPECT_STREQ(
995 "(a is A(true)/ B(false)/ C(false),"
996 " b is A(true)/ B(true)/ C(false),"
997 " c is A(true)/ B(true)/ C(true))",
998 SimpleInvokeStr(lib, "main"));
999
1000 const char* kReloadScript =
1001 "class C {\n"
1002 " String name;\n"
1003 " C(this.name);\n"
1004 "}\n"
1005 "class X extends C {\n"
1006 " X(name) : super(name);\n"
1007 "}\n"
1008 "class A extends X {\n"
1009 " A(name) : super(name);\n"
1010 "}\n"
1011 "var list;\n"
1012 "main() {\n"
1013 " list.add(new X('x'));\n"
1014 " return (list.map((x) {\n"
1015 " return '${x.name} is A(${x is A})/ C(${x is C})/ X(${x is X})';\n"
1016 " })).toString();\n"
1017 "}\n";
1018
1019 lib = TestCase::ReloadTestScript(kReloadScript);
1020 EXPECT_VALID(lib);
1021 EXPECT_STREQ(
1022 "(a is A(true)/ C(true)/ X(true),"
1023 " b is A(true)/ C(true)/ X(true)," // still extends A...
1024 " c is A(false)/ C(true)/ X(false),"
1025 " x is A(false)/ C(true)/ X(true))",
1026 SimpleInvokeStr(lib, "main"));
1027
1028 // Revive the class B and make sure all allocated instances take
1029 // their place in the inheritance hierarchy.
1030 const char* kReloadScript2 =
1031 "class X {\n"
1032 " String name;\n"
1033 " X(this.name);\n"
1034 "}\n"
1035 "class A extends X{\n"
1036 " A(name) : super(name);\n"
1037 "}\n"
1038 "class B extends X {\n"
1039 " B(name) : super(name);\n"
1040 "}\n"
1041 "class C extends A {\n"
1042 " C(name) : super(name);\n"
1043 "}\n"
1044 "var list;\n"
1045 "main() {\n"
1046 " return (list.map((x) {\n"
1047 " return '${x.name} is '\n"
1048 " 'A(${x is A})/ B(${x is B})/ C(${x is C})/ X(${x is X})';\n"
1049 " })).toString();\n"
1050 "}\n";
1051
1052 lib = TestCase::ReloadTestScript(kReloadScript2);
1053 EXPECT_VALID(lib);
1054 EXPECT_STREQ(
1055 "(a is A(true)/ B(false)/ C(false)/ X(true),"
1056 " b is A(false)/ B(true)/ C(false)/ X(true),"
1057 " c is A(true)/ B(false)/ C(true)/ X(true),"
1058 " x is A(false)/ B(false)/ C(false)/ X(true))",
1059 SimpleInvokeStr(lib, "main"));
1060}
1061
1062TEST_CASE(IsolateReload_LiveStack) {
1063 const char* kScript =
1064 "import 'file:///test:isolate_reload_helper';\n"
1065 "helper() => 7;\n"
1066 "alpha() { var x = helper(); reloadTest(); return x + helper(); }\n"
1067 "foo() => alpha();\n"
1068 "bar() => foo();\n"
1069 "main() {\n"
1070 " return bar();\n"
1071 "}\n";
1072
1073 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1074 EXPECT_VALID(lib);
1075
1076 const char* kReloadScript =
1077 "import 'file:///test:isolate_reload_helper';\n"
1078 "helper() => 100;\n"
1079 "alpha() => 5 + helper();\n"
1080 "foo() => alpha();\n"
1081 "bar() => foo();\n"
1082 "main() {\n"
1083 " return bar();\n"
1084 "}\n";
1085
1087
1088 EXPECT_EQ(107, SimpleInvoke(lib, "main"));
1089
1090 lib = Dart_RootLibrary();
1091 EXPECT_NON_NULL(lib);
1092 EXPECT_EQ(105, SimpleInvoke(lib, "main"));
1093}
1094
1095TEST_CASE(IsolateReload_LibraryLookup) {
1096 const char* kImportScript = "importedFunc() => 'a';\n";
1097 TestCase::AddTestLib("test:lib1", kImportScript);
1098
1099 const char* kScript =
1100 "main() {\n"
1101 " return 'b';\n"
1102 "}\n";
1104 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1105 EXPECT_VALID(lib);
1106 EXPECT_STREQ("b", SimpleInvokeStr(lib, "main"));
1107
1108 // Fail to find 'test:lib1' in the isolate.
1109 result = Dart_LookupLibrary(NewString("test:lib1"));
1111
1112 const char* kReloadScript =
1113 "import 'test:lib1';\n"
1114 "main() {\n"
1115 " return importedFunc();\n"
1116 "}\n";
1117
1118 // Reload and add 'test:lib1' to isolate.
1119 lib = TestCase::ReloadTestScript(kReloadScript);
1120 EXPECT_VALID(lib);
1121 EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
1122
1123 // Find 'test:lib1' in the isolate.
1124 result = Dart_LookupLibrary(NewString("test:lib1"));
1126
1127 // Reload and remove 'test:lib1' from isolate.
1128 lib = TestCase::ReloadTestScript(kScript);
1129 EXPECT_VALID(lib);
1130
1131 // Fail to find 'test:lib1' in the isolate.
1132 result = Dart_LookupLibrary(NewString("test:lib1"));
1134}
1135
1136TEST_CASE(IsolateReload_LibraryHide) {
1137 const char* kImportScript = "importedFunc() => 'a';\n";
1138 TestCase::AddTestLib("test:lib1", kImportScript);
1139
1140 // Import 'test:lib1' with importedFunc hidden. Will result in an
1141 // error.
1142 const char* kScript =
1143 "import 'test:lib1' hide importedFunc;\n"
1144 "main() {\n"
1145 " return importedFunc();\n"
1146 "}\n";
1147
1148 // Dart_Handle result;
1149
1151 EXPECT_VALID(lib);
1152 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
1153
1154 // Import 'test:lib1'.
1155 const char* kReloadScript =
1156 "import 'test:lib1';\n"
1157 "main() {\n"
1158 " return importedFunc();\n"
1159 "}\n";
1160
1161 lib = TestCase::ReloadTestScript(kReloadScript);
1162 EXPECT_VALID(lib);
1163 EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
1164}
1165
1166TEST_CASE(IsolateReload_LibraryShow) {
1167 const char* kImportScript =
1168 "importedFunc() => 'a';\n"
1169 "importedIntFunc() => 4;\n";
1170 TestCase::AddTestLib("test:lib1", kImportScript);
1171
1172 // Import 'test:lib1' with importedIntFunc visible. Will result in
1173 // an error when 'main' is invoked.
1174 const char* kScript =
1175 "import 'test:lib1' show importedIntFunc;\n"
1176 "main() {\n"
1177 " return importedFunc();\n"
1178 "}\n"
1179 "mainInt() {\n"
1180 " return importedIntFunc();\n"
1181 "}\n";
1182
1184 EXPECT_VALID(lib);
1185
1186 // Works.
1187 EXPECT_EQ(4, SimpleInvoke(lib, "mainInt"));
1188 // Results in an error.
1189 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
1190
1191 // Import 'test:lib1' with importedFunc visible. Will result in
1192 // an error when 'mainInt' is invoked.
1193 const char* kReloadScript =
1194 "import 'test:lib1' show importedFunc;\n"
1195 "main() {\n"
1196 " return importedFunc();\n"
1197 "}\n"
1198 "mainInt() {\n"
1199 " return importedIntFunc();\n"
1200 "}\n";
1201
1202 lib = TestCase::ReloadTestScript(kReloadScript);
1203 EXPECT_ERROR(lib, "importedIntFunc");
1204}
1205
1206// Verifies that we clear the ICs for the functions live on the stack in a way
1207// that is compatible with the fast path smi stubs.
1208TEST_CASE(IsolateReload_SmiFastPathStubs) {
1209 const char* kImportScript = "importedIntFunc() => 4;\n";
1210 TestCase::AddTestLib("test:lib1", kImportScript);
1211
1212 const char* kScript =
1213 "import 'file:///test:isolate_reload_helper';\n"
1214 "import 'test:lib1' show importedIntFunc;\n"
1215 "main() {\n"
1216 " var x = importedIntFunc();\n"
1217 " var y = importedIntFunc();\n"
1218 " reloadTest();\n"
1219 " return x + y;\n"
1220 "}\n";
1221
1222 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1223 EXPECT_VALID(lib);
1224
1225 // Identity reload.
1227
1228 EXPECT_EQ(8, SimpleInvoke(lib, "main"));
1229}
1230
1231// Verifies that we assign the correct patch classes for imported
1232// mixins when we reload.
1233TEST_CASE(IsolateReload_ImportedMixinFunction) {
1234 const char* kImportScript =
1235 "mixin ImportedMixin {\n"
1236 " mixinFunc() => 'mixin';\n"
1237 "}\n";
1238 TestCase::AddTestLib("test:lib1", kImportScript);
1239
1240 const char* kScript =
1241 "import 'test:lib1' show ImportedMixin;\n"
1242 "class A extends Object with ImportedMixin {\n"
1243 "}"
1244 "var func = new A().mixinFunc;\n"
1245 "main() {\n"
1246 " return func();\n"
1247 "}\n";
1248
1249 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1250 EXPECT_VALID(lib);
1251
1252 EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
1253
1254 const char* kReloadScript =
1255 "import 'test:lib1' show ImportedMixin;\n"
1256 "class A extends Object with ImportedMixin {\n"
1257 "}"
1258 "var func;\n"
1259 "main() {\n"
1260 " return func();\n"
1261 "}\n";
1262
1263 lib = TestCase::ReloadTestScript(kReloadScript);
1264 EXPECT_VALID(lib);
1265 EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
1266}
1267
1268TEST_CASE(IsolateReload_TopLevelParseError) {
1269 const char* kScript =
1270 "main() {\n"
1271 " return 4;\n"
1272 "}\n";
1273
1274 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1275 EXPECT_VALID(lib);
1276 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
1277
1278 const char* kReloadScript =
1279 "kjsadkfjaksldfjklsadf;\n"
1280 "main() {\n"
1281 " return 4;\n"
1282 "}\n";
1283
1284 lib = TestCase::ReloadTestScript(kReloadScript);
1285 EXPECT_ERROR(lib,
1286 "Variables must be declared using the keywords"
1287 " 'const', 'final', 'var' or a type name.");
1288}
1289
1290TEST_CASE(IsolateReload_PendingUnqualifiedCall_StaticToInstance) {
1291 const char* kScript =
1292 "import 'file:///test:isolate_reload_helper';\n"
1293 "class C {\n"
1294 " static foo() => 'static';\n"
1295 " test() {\n"
1296 " reloadTest();\n"
1297 " return foo();\n"
1298 " }\n"
1299 "}\n"
1300 "main() {\n"
1301 " return new C().test();\n"
1302 "}\n";
1303
1304 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1305 EXPECT_VALID(lib);
1306
1307 const char* kReloadScript =
1308 "import 'file:///test:isolate_reload_helper';\n"
1309 "class C {\n"
1310 " foo() => 'instance';\n"
1311 " test() {\n"
1312 " reloadTest();\n"
1313 " return foo();\n"
1314 " }\n"
1315 "}\n"
1316 "main() {\n"
1317 " return new C().test();\n"
1318 "}\n";
1319
1321
1322 const char* expected = "instance";
1323 const char* result = SimpleInvokeStr(lib, "main");
1324 EXPECT_STREQ(expected, result);
1325
1326 // Bail out if we've already failed so we don't crash in the tag handler.
1327 if ((result == nullptr) || (strcmp(expected, result) != 0)) {
1328 return;
1329 }
1330
1331 lib = Dart_RootLibrary();
1332 EXPECT_NON_NULL(lib);
1333 EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
1334}
1335
1336TEST_CASE(IsolateReload_PendingUnqualifiedCall_InstanceToStatic) {
1337 const char* kScript =
1338 "import 'file:///test:isolate_reload_helper';\n"
1339 "class C {\n"
1340 " foo() => 'instance';\n"
1341 " test() {\n"
1342 " reloadTest();\n"
1343 " return foo();\n"
1344 " }\n"
1345 "}\n"
1346 "main() {\n"
1347 " return new C().test();\n"
1348 "}\n";
1349
1350 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1351 EXPECT_VALID(lib);
1352
1353 const char* kReloadScript =
1354 "import 'file:///test:isolate_reload_helper';\n"
1355 "class C {\n"
1356 " static foo() => 'static';\n"
1357 " test() {\n"
1358 " reloadTest();\n"
1359 " return foo();\n"
1360 " }\n"
1361 "}\n"
1362 "main() {\n"
1363 " return new C().test();\n"
1364 "}\n";
1365
1367 const char* expected = "static";
1368 const char* result = SimpleInvokeStr(lib, "main");
1369 EXPECT_NOTNULL(result);
1370 // Bail out if we've already failed so we don't crash in StringEquals.
1371 if (result == nullptr) {
1372 return;
1373 }
1374 EXPECT_STREQ(expected, result);
1375
1376 lib = Dart_RootLibrary();
1377 EXPECT_NON_NULL(lib);
1378 EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
1379}
1380
1381TEST_CASE(IsolateReload_PendingConstructorCall_AbstractToConcrete) {
1382 const char* kScript =
1383 "import 'file:///test:isolate_reload_helper';\n"
1384 "abstract class Foo {}\n"
1385 "class C {\n"
1386 " test() {\n"
1387 " reloadTest();\n"
1388 " }\n"
1389 "}\n"
1390 "main() {\n"
1391 " try {\n"
1392 " new C().test();\n"
1393 " return 'okay';\n"
1394 " } catch (e) {\n"
1395 " return 'exception';\n"
1396 " }\n"
1397 "}\n";
1398
1399 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1400 EXPECT_VALID(lib);
1401
1402 const char* kReloadScript =
1403 "import 'file:///test:isolate_reload_helper';\n"
1404 "class Foo {}\n"
1405 "class C {\n"
1406 " test() {\n"
1407 " reloadTest();\n"
1408 " return new Foo();\n"
1409 " }\n"
1410 "}\n"
1411 "main() {\n"
1412 " try {\n"
1413 " new C().test();\n"
1414 " return 'okay';\n"
1415 " } catch (e) {\n"
1416 " return 'exception';\n"
1417 " }\n"
1418 "}\n";
1419
1421
1422 const char* expected = "okay";
1423 const char* result = SimpleInvokeStr(lib, "main");
1424 EXPECT_STREQ(expected, result);
1425
1426 // Bail out if we've already failed so we don't crash in the tag handler.
1427 if ((result == nullptr) || (strcmp(expected, result) != 0)) {
1428 return;
1429 }
1430
1431 lib = Dart_RootLibrary();
1432 EXPECT_NON_NULL(lib);
1433 EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
1434}
1435
1436TEST_CASE(IsolateReload_PendingConstructorCall_ConcreteToAbstract) {
1437 const char* kScript =
1438 "import 'file:///test:isolate_reload_helper';\n"
1439 "class Foo {}\n"
1440 "class C {\n"
1441 " test() {\n"
1442 " reloadTest();\n"
1443 " return new Foo();\n"
1444 " }\n"
1445 "}\n"
1446 "main() {\n"
1447 " try {\n"
1448 " new C().test();\n"
1449 " return 'okay';\n"
1450 " } catch (e) {\n"
1451 " return 'exception';\n"
1452 " }\n"
1453 "}\n";
1454
1455 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1456 EXPECT_VALID(lib);
1457
1458 const char* kReloadScript =
1459 "import 'file:///test:isolate_reload_helper';\n"
1460 "abstract class Foo {}\n"
1461 "class C {\n"
1462 " test() {\n"
1463 " reloadTest();\n"
1464 " return new Foo();\n"
1465 " }\n"
1466 "}\n"
1467 "main() {\n"
1468 " try {\n"
1469 " new C().test();\n"
1470 " return 'okay';\n"
1471 " } catch (e) {\n"
1472 " return 'exception';\n"
1473 " }\n"
1474 "}\n";
1475
1477 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "is abstract");
1478}
1479
1480TEST_CASE(IsolateReload_PendingStaticCall_DefinedToNSM) {
1481 const char* kScript =
1482 "import 'file:///test:isolate_reload_helper';\n"
1483 "class C {\n"
1484 " static foo() => 'static';\n"
1485 " test() {\n"
1486 " reloadTest();\n"
1487 " return C.foo();\n"
1488 " }\n"
1489 "}\n"
1490 "main() {\n"
1491 " try {\n"
1492 " return new C().test();\n"
1493 " } catch (e) {\n"
1494 " return 'exception';\n"
1495 " }\n"
1496 "}\n";
1497
1498 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1499 EXPECT_VALID(lib);
1500
1501 const char* kReloadScript =
1502 "import 'file:///test:isolate_reload_helper';\n"
1503 "class C {\n"
1504 " test() {\n"
1505 " reloadTest();\n"
1506 " return C.foo();\n"
1507 " }\n"
1508 "}\n"
1509 "main() {\n"
1510 " try {\n"
1511 " return new C().test();\n"
1512 " } catch (e) {\n"
1513 " return 'exception';\n"
1514 " }\n"
1515 "}\n";
1516
1518 const char* expected = "exception";
1519 const char* result = SimpleInvokeStr(lib, "main");
1520 EXPECT_NOTNULL(result);
1521
1522 // Bail out if we've already failed so we don't crash in StringEquals.
1523 if (result == nullptr) {
1524 return;
1525 }
1526 EXPECT_STREQ(expected, result);
1527
1528 lib = Dart_RootLibrary();
1529 EXPECT_NON_NULL(lib);
1530 EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
1531}
1532
1533TEST_CASE(IsolateReload_PendingStaticCall_NSMToDefined) {
1534 const char* kScript =
1535 "import 'file:///test:isolate_reload_helper';\n"
1536 "class C {\n"
1537 " test() {\n"
1538 " reloadTest();\n"
1539 " return C.foo();\n"
1540 " }\n"
1541 "}\n"
1542 "main() {\n"
1543 " try {\n"
1544 " return new C().test();\n"
1545 " } catch (e) {\n"
1546 " return 'exception';\n"
1547 " }\n"
1548 "}\n";
1549
1550 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1551 EXPECT_VALID(lib);
1552
1553 const char* kReloadScript =
1554 "import 'file:///test:isolate_reload_helper';\n"
1555 "class C {\n"
1556 " static foo() => 'static';\n"
1557 " test() {\n"
1558 " reloadTest();\n"
1559 " return C.foo();\n"
1560 " }\n"
1561 "}\n"
1562 "main() {\n"
1563 " try {\n"
1564 " return new C().test();\n"
1565 " } catch (e) {\n"
1566 " return 'exception';\n"
1567 " }\n"
1568 "}\n";
1569
1571
1572 const char* expected = "static";
1573 const char* result = SimpleInvokeStr(lib, "main");
1574
1575 // Bail out if we've already failed so we don't crash in the tag handler.
1576 if (result == nullptr) {
1577 return;
1578 }
1579 EXPECT_STREQ(expected, result);
1580
1581 lib = Dart_RootLibrary();
1582 EXPECT_NON_NULL(lib);
1583 EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
1584}
1585
1586TEST_CASE(IsolateReload_PendingSuperCall) {
1587 const char* kScript =
1588 "import 'file:///test:isolate_reload_helper';\n"
1589 "class S {\n"
1590 " foo() => 1;\n"
1591 "}\n"
1592 "class C extends S {\n"
1593 " foo() => 100;\n"
1594 " test() {\n"
1595 " var n = super.foo();\n"
1596 " reloadTest();\n"
1597 " return n + super.foo();\n"
1598 " }\n"
1599 "}\n"
1600 "main() {\n"
1601 " return new C().test();\n"
1602 "}\n";
1603
1604 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1605 EXPECT_VALID(lib);
1606
1607 const char* kReloadScript =
1608 "import 'file:///test:isolate_reload_helper';\n"
1609 "class S {\n"
1610 " foo() => 10;\n"
1611 "}\n"
1612 "class C extends S {\n"
1613 " foo() => 100;\n"
1614 " test() {\n"
1615 " var n = super.foo();\n"
1616 " reloadTest();\n"
1617 " return n + super.foo();\n"
1618 " }\n"
1619 "}\n"
1620 "main() {\n"
1621 " return new C().test();\n"
1622 "}\n";
1623
1625
1626 EXPECT_EQ(11, SimpleInvoke(lib, "main"));
1627}
1628
1629TEST_CASE(IsolateReload_TearOff_Instance_Equality) {
1630 const char* kScript =
1631 "import 'file:///test:isolate_reload_helper';\n"
1632 "class C {\n"
1633 " foo() => 'old';\n"
1634 "}\n"
1635 "main() {\n"
1636 " var c = new C();\n"
1637 " var f1 = c.foo;\n"
1638 " reloadTest();\n"
1639 " var f2 = c.foo;\n"
1640 " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
1641 "}\n";
1642
1643 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1644 EXPECT_VALID(lib);
1645
1646 const char* kReloadScript =
1647 "import 'file:///test:isolate_reload_helper';\n"
1648 "class C {\n"
1649 " foo() => 'new';\n"
1650 "}\n"
1651 "main() {\n"
1652 " var c = new C();\n"
1653 " var f1 = c.foo;\n"
1654 " reloadTest();\n"
1655 " var f2 = c.foo;\n"
1656 " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
1657 "}\n";
1658
1660
1661 EXPECT_STREQ("new new true false", SimpleInvokeStr(lib, "main"));
1662
1663 lib = Dart_RootLibrary();
1664 EXPECT_NON_NULL(lib);
1665}
1666
1667TEST_CASE(IsolateReload_TearOff_Parameter_Count_Mismatch) {
1668 const char* kScript =
1669 "import 'file:///test:isolate_reload_helper';\n"
1670 "class C {\n"
1671 " static foo() => 'old';\n"
1672 "}\n"
1673 "main() {\n"
1674 " var f1 = C.foo;\n"
1675 " reloadTest();\n"
1676 " return f1();\n"
1677 "}\n";
1678
1679 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1680 EXPECT_VALID(lib);
1681
1682 const char* kReloadScript =
1683 "import 'file:///test:isolate_reload_helper';\n"
1684 "class C {\n"
1685 " static foo(i) => 'new:$i';\n"
1686 "}\n"
1687 "main() {\n"
1688 " var f1 = C.foo;\n"
1689 " reloadTest();\n"
1690 " return f1();\n"
1691 "}\n";
1692
1693 TestCase::SetReloadTestScript(kReloadScript);
1694 Dart_Handle error_handle = SimpleInvokeError(lib, "main");
1695
1696 const char* error;
1697 error =
1698 "/test-lib:8:12: Error: Too few positional"
1699 " arguments: 1 required, 0 given.\n"
1700 " return f1();";
1701 EXPECT_ERROR(error_handle, error);
1702}
1703
1704TEST_CASE(IsolateReload_TearOff_Remove) {
1705 const char* kScript =
1706 "import 'file:///test:isolate_reload_helper';\n"
1707 "class C {\n"
1708 " static foo({String bar = 'bar'}) => 'old';\n"
1709 "}\n"
1710 "main() {\n"
1711 " var f1 = C.foo;\n"
1712 " reloadTest();\n"
1713 " try {\n"
1714 " return f1();\n"
1715 " } catch(e) { return '$e'; }\n"
1716 "}\n";
1717
1718 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1719 EXPECT_VALID(lib);
1720
1721 const char* kReloadScript =
1722 "import 'file:///test:isolate_reload_helper';\n"
1723 "class C {\n"
1724 "}\n"
1725 "main() {\n"
1726 " var f1;\n"
1727 " reloadTest();\n"
1728 " try {\n"
1729 " return f1();\n"
1730 " } catch(e) { return '$e'; }\n"
1731 "}\n";
1732
1733 TestCase::SetReloadTestScript(kReloadScript);
1734
1735 EXPECT_SUBSTRING(
1736 "NoSuchMethodError: No static method 'foo' declared in class 'C'.",
1737 SimpleInvokeStr(lib, "main"));
1738
1739 lib = Dart_RootLibrary();
1740 EXPECT_NON_NULL(lib);
1741}
1742
1743TEST_CASE(IsolateReload_TearOff_Class_Identity) {
1744 const char* kScript =
1745 "import 'file:///test:isolate_reload_helper';\n"
1746 "class C {\n"
1747 " static foo() => 'old';\n"
1748 "}\n"
1749 "getFoo() => C.foo;\n"
1750 "main() {\n"
1751 " var f1 = getFoo();\n"
1752 " reloadTest();\n"
1753 " var f2 = getFoo();\n"
1754 " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
1755 "}\n";
1756
1757 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1758 EXPECT_VALID(lib);
1759
1760 const char* kReloadScript =
1761 "import 'file:///test:isolate_reload_helper';\n"
1762 "class C {\n"
1763 " static foo() => 'new';\n"
1764 "}\n"
1765 "getFoo() => C.foo;\n"
1766 "main() {\n"
1767 " var f1 = getFoo();\n"
1768 " reloadTest();\n"
1769 " var f2 = getFoo();\n"
1770 " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
1771 "}\n";
1772
1774
1775 EXPECT_STREQ("new new true true", SimpleInvokeStr(lib, "main"));
1776
1777 lib = Dart_RootLibrary();
1778 EXPECT_NON_NULL(lib);
1779}
1780
1781TEST_CASE(IsolateReload_TearOff_Library_Identity) {
1782 const char* kScript =
1783 "import 'file:///test:isolate_reload_helper';\n"
1784 "foo() => 'old';\n"
1785 "getFoo() => foo;\n"
1786 "main() {\n"
1787 " var f1 = getFoo();\n"
1788 " reloadTest();\n"
1789 " var f2 = getFoo();\n"
1790 " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
1791 "}\n";
1792
1793 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1794 EXPECT_VALID(lib);
1795
1796 const char* kReloadScript =
1797 "import 'file:///test:isolate_reload_helper';\n"
1798 "foo() => 'new';\n"
1799 "getFoo() => foo;\n"
1800 "main() {\n"
1801 " var f1 = getFoo();\n"
1802 " reloadTest();\n"
1803 " var f2 = getFoo();\n"
1804 " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
1805 "}\n";
1806
1808
1809 EXPECT_STREQ("new new true true", SimpleInvokeStr(lib, "main"));
1810
1811 lib = Dart_RootLibrary();
1812 EXPECT_NON_NULL(lib);
1813}
1814
1815TEST_CASE(IsolateReload_TearOff_List_Set) {
1816 const char* kScript =
1817 "import 'file:///test:isolate_reload_helper';\n"
1818 "class C {\n"
1819 " foo() => 'old';\n"
1820 "}\n"
1821 "List list = List<dynamic>.filled(2, null);\n"
1822 "Set set = Set();\n"
1823 "main() {\n"
1824 " var c = C();\n"
1825 " list[0] = c.foo;\n"
1826 " list[1] = c.foo;\n"
1827 " set.add(c.foo);\n"
1828 " set.add(c.foo);\n"
1829 " int countBefore = set.length;\n"
1830 " reloadTest();\n"
1831 " list[1] = c.foo;\n"
1832 " set.add(c.foo);\n"
1833 " set.add(c.foo);\n"
1834 " int countAfter = set.length;\n"
1835 " return '${list[0]()} ${list[1]()} ${list[0] == list[1]} '\n"
1836 " '${countBefore == 1} ${countAfter == 1} ${(set.first)()} '\n"
1837 " '${set.first == c.foo} ${set.first == c.foo} '\n"
1838 " '${set.remove(c.foo)}';\n"
1839 "}\n";
1840
1841 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1842 EXPECT_VALID(lib);
1843
1844 const char* kReloadScript =
1845 "import 'file:///test:isolate_reload_helper';\n"
1846 "class C {\n"
1847 " foo() => 'new';\n"
1848 "}\n"
1849 "List list = List<dynamic>.filled(2, null);\n"
1850 "Set set = Set();\n"
1851 "main() {\n"
1852 " var c = C();\n"
1853 " list[0] = c.foo;\n"
1854 " list[1] = c.foo;\n"
1855 " set.add(c.foo);\n"
1856 " set.add(c.foo);\n"
1857 " int countBefore = set.length;\n"
1858 " reloadTest();\n"
1859 " list[1] = c.foo;\n"
1860 " set.add(c.foo);\n"
1861 " set.add(c.foo);\n"
1862 " int countAfter = set.length;\n"
1863 " return '${list[0]()} ${list[1]()} ${list[0] == list[1]} '\n"
1864 " '${countBefore == 1} ${countAfter == 1} ${(set.first)()} '\n"
1865 " '${set.first == c.foo} ${set.first == c.foo} '\n"
1866 " '${set.remove(c.foo)}';\n"
1867 "}\n";
1868
1870
1871 EXPECT_STREQ("new new true true true new true true true",
1872 SimpleInvokeStr(lib, "main"));
1873
1874 lib = Dart_RootLibrary();
1875 EXPECT_NON_NULL(lib);
1876}
1877
1878TEST_CASE(IsolateReload_TearOff_AddArguments) {
1879 const char* kScript =
1880 "import 'file:///test:isolate_reload_helper';\n"
1881 "class C {\n"
1882 " foo(x) => x;\n"
1883 "}\n"
1884 "invoke(f, a) {\n"
1885 " try {\n"
1886 " return f(a);\n"
1887 " } catch (e) {\n"
1888 " return e.toString().split('\\n').first;\n"
1889 " }\n"
1890 "}\n"
1891 "main() {\n"
1892 " var c = new C();\n"
1893 " var f = c.foo;\n"
1894 " var r1 = invoke(f, 1);\n"
1895 " reloadTest();\n"
1896 " var r2 = invoke(f, 1);\n"
1897 " return '$r1 $r2';\n"
1898 "}\n";
1899
1900 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1901 EXPECT_VALID(lib);
1902
1903 const char* kReloadScript =
1904 "import 'file:///test:isolate_reload_helper';\n"
1905 "class C {\n"
1906 " foo(x, y, z) => x + y + z;\n"
1907 "}\n"
1908 "invoke(f, a) {\n"
1909 " try {\n"
1910 " return f(a);\n"
1911 " } catch (e) {\n"
1912 " return e.toString().split('\\n').first;\n"
1913 " }\n"
1914 "}\n"
1915 "main() {\n"
1916 " var c = new C();\n"
1917 " var f = c.foo;\n"
1918 " var r1 = invoke(f, 1);\n"
1919 " reloadTest();\n"
1920 " var r2 = invoke(f, 1);\n"
1921 " return '$r1 $r2';\n"
1922 "}\n";
1923
1925
1926 EXPECT_STREQ(
1927 "1 NoSuchMethodError: Class 'C' has no instance method "
1928 "'foo' with matching arguments.",
1929 SimpleInvokeStr(lib, "main"));
1930
1931 lib = Dart_RootLibrary();
1932 EXPECT_NON_NULL(lib);
1933}
1934
1935TEST_CASE(IsolateReload_TearOff_AddArguments2) {
1936 const char* kScript =
1937 "import 'file:///test:isolate_reload_helper';\n"
1938 "class C {\n"
1939 " static foo(x) => x;\n"
1940 "}\n"
1941 "invoke(f, a) {\n"
1942 " try {\n"
1943 " return f(a);\n"
1944 " } catch (e) {\n"
1945 " return e.toString().split('\\n').first;\n"
1946 " }\n"
1947 "}\n"
1948 "main() {\n"
1949 " var f = C.foo;\n"
1950 " var r1 = invoke(f, 1);\n"
1951 " reloadTest();\n"
1952 " var r2 = invoke(f, 1);\n"
1953 " return '$r1 $r2';\n"
1954 "}\n";
1955
1956 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
1957 EXPECT_VALID(lib);
1958
1959 const char* kReloadScript =
1960 "import 'file:///test:isolate_reload_helper';\n"
1961 "class C {\n"
1962 " static foo(x, y, z) => x + y + z;\n"
1963 "}\n"
1964 "invoke(f, a) {\n"
1965 " try {\n"
1966 " return f(a);\n"
1967 " } catch (e) {\n"
1968 " return e.toString().split('\\n').first;\n"
1969 " }\n"
1970 "}\n"
1971 "main() {\n"
1972 " var f = C.foo;\n"
1973 " var r1 = invoke(f, 1);\n"
1974 " reloadTest();\n"
1975 " var r2 = invoke(f, 1);\n"
1976 " return '$r1 $r2';\n"
1977 "}\n";
1978
1980
1981 EXPECT_STREQ(
1982 "1 NoSuchMethodError: Closure call with mismatched arguments: "
1983 "function 'C.foo'",
1984 SimpleInvokeStr(lib, "main"));
1985
1986 lib = Dart_RootLibrary();
1987 EXPECT_NON_NULL(lib);
1988}
1989
1990TEST_CASE(IsolateReload_EnumEquality) {
1991 const char* kScript =
1992 "enum Fruit {\n"
1993 " Apple,\n"
1994 " Banana,\n"
1995 "}\n"
1996 "var x;\n"
1997 "main() {\n"
1998 " x = Fruit.Banana;\n"
1999 " return Fruit.Apple.toString();\n"
2000 "}\n";
2001
2002 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2003 EXPECT_VALID(lib);
2004
2005 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2006
2007 const char* kReloadScript =
2008 "enum Fruit {\n"
2009 " Apple,\n"
2010 " Banana,\n"
2011 "}\n"
2012 "var x;\n"
2013 "main() {\n"
2014 " if (x == Fruit.Banana) {\n"
2015 " return 'yes';\n"
2016 " } else {\n"
2017 " return 'no';\n"
2018 " }\n"
2019 "}\n";
2020
2021 lib = TestCase::ReloadTestScript(kReloadScript);
2022 EXPECT_VALID(lib);
2023 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
2024}
2025
2026TEST_CASE(IsolateReload_EnumIdentical) {
2027 const char* kScript =
2028 "enum Fruit {\n"
2029 " Apple,\n"
2030 " Banana,\n"
2031 "}\n"
2032 "var x;\n"
2033 "main() {\n"
2034 " x = Fruit.Banana;\n"
2035 " return Fruit.Apple.toString();\n"
2036 "}\n";
2037
2038 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2039 EXPECT_VALID(lib);
2040 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2041
2042 const char* kReloadScript =
2043 "enum Fruit {\n"
2044 " Apple,\n"
2045 " Banana,\n"
2046 "}\n"
2047 "var x;\n"
2048 "main() {\n"
2049 " if (identical(x, Fruit.Banana)) {\n"
2050 " return 'yes';\n"
2051 " } else {\n"
2052 " return 'no';\n"
2053 " }\n"
2054 "}\n";
2055
2056 lib = TestCase::ReloadTestScript(kReloadScript);
2057 EXPECT_VALID(lib);
2058 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
2059}
2060
2061TEST_CASE(IsolateReload_EnumReorderIdentical) {
2062 const char* kScript =
2063 "enum Fruit {\n"
2064 " Apple,\n"
2065 " Banana,\n"
2066 "}\n"
2067 "var x;\n"
2068 "main() {\n"
2069 " x = Fruit.Banana;\n"
2070 " return Fruit.Apple.toString();\n"
2071 "}\n";
2072
2073 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2074 EXPECT_VALID(lib);
2075 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2076
2077 const char* kReloadScript =
2078 "enum Fruit {\n"
2079 " Banana,\n"
2080 " Apple,\n"
2081 "}\n"
2082 "var x;\n"
2083 "main() {\n"
2084 " if (identical(x, Fruit.Banana)) {\n"
2085 " return 'yes';\n"
2086 " } else {\n"
2087 " return 'no';\n"
2088 " }\n"
2089 "}\n";
2090
2091 lib = TestCase::ReloadTestScript(kReloadScript);
2092 EXPECT_VALID(lib);
2093 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
2094}
2095
2096TEST_CASE(IsolateReload_EnumAddition) {
2097 const char* kScript =
2098 "enum Fruit {\n"
2099 " Apple,\n"
2100 " Banana,\n"
2101 "}\n"
2102 "var x;\n"
2103 "main() {\n"
2104 " return Fruit.Apple.toString();\n"
2105 "}\n";
2106
2107 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2108 EXPECT_VALID(lib);
2109 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2110
2111 const char* kReloadScript =
2112 "enum Fruit {\n"
2113 " Apple,\n"
2114 " Cantaloupe,\n"
2115 " Banana,\n"
2116 "}\n"
2117 "var x;\n"
2118 "main() {\n"
2119 " String r = '${Fruit.Apple.index}/${Fruit.Apple} ';\n"
2120 " r += '${Fruit.Cantaloupe.index}/${Fruit.Cantaloupe} ';\n"
2121 " r += '${Fruit.Banana.index}/${Fruit.Banana}';\n"
2122 " return r;\n"
2123 "}\n";
2124
2125 lib = TestCase::ReloadTestScript(kReloadScript);
2126 EXPECT_VALID(lib);
2127 EXPECT_STREQ("0/Fruit.Apple 1/Fruit.Cantaloupe 2/Fruit.Banana",
2128 SimpleInvokeStr(lib, "main"));
2129}
2130
2131TEST_CASE(IsolateReload_EnumToNotEnum) {
2132 const char* kScript =
2133 "enum Fruit {\n"
2134 " Apple\n"
2135 "}\n"
2136 "main() {\n"
2137 " return Fruit.Apple.toString();\n"
2138 "}\n";
2139
2140 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2141 EXPECT_VALID(lib);
2142 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2143
2144 const char* kReloadScript =
2145 "class Fruit {\n"
2146 " final int zero = 0;\n"
2147 "}\n"
2148 "main() {\n"
2149 " return new Fruit().zero.toString();\n"
2150 "}\n";
2151
2153 EXPECT_ERROR(result, "Enum class cannot be redefined to be a non-enum class");
2154}
2155
2156TEST_CASE(IsolateReload_NotEnumToEnum) {
2157 const char* kScript =
2158 "class Fruit {\n"
2159 " final int zero = 0;\n"
2160 "}\n"
2161 "main() {\n"
2162 " return new Fruit().zero.toString();\n"
2163 "}\n";
2164
2165 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2166 EXPECT_VALID(lib);
2167 EXPECT_STREQ("0", SimpleInvokeStr(lib, "main"));
2168
2169 const char* kReloadScript =
2170 "enum Fruit {\n"
2171 " Apple\n"
2172 "}\n"
2173 "main() {\n"
2174 " return Fruit.Apple.toString();\n"
2175 "}\n";
2176
2178 EXPECT_ERROR(result, "Class cannot be redefined to be a enum class");
2179}
2180
2181TEST_CASE(IsolateReload_EnumDelete) {
2182 const char* kScript =
2183 "enum Fruit {\n"
2184 " Apple,\n"
2185 " Banana,\n"
2186 " Cantaloupe,\n"
2187 "}\n"
2188 "var x;\n"
2189 "main() {\n"
2190 " x = Fruit.Cantaloupe;\n"
2191 " return Fruit.Apple.toString();\n"
2192 "}\n";
2193
2194 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2195 EXPECT_VALID(lib);
2196 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2197
2198 // Delete 'Cantaloupe' but make sure that we can still invoke toString,
2199 // and access the hashCode and index properties.
2200
2201 const char* kReloadScript =
2202 "enum Fruit {\n"
2203 " Apple,\n"
2204 " Banana,\n"
2205 "}\n"
2206 "var x;\n"
2207 "main() {\n"
2208 " String r = '$x ${x.hashCode is int} ${x.index}';\n"
2209 " return r;\n"
2210 "}\n";
2211
2212 lib = TestCase::ReloadTestScript(kReloadScript);
2213 EXPECT_VALID(lib);
2214 EXPECT_STREQ("Fruit.Deleted enum value from Fruit true -1",
2215 SimpleInvokeStr(lib, "main"));
2216}
2217
2218TEST_CASE(IsolateReload_EnumIdentityReload) {
2219 const char* kScript =
2220 "enum Fruit {\n"
2221 " Apple,\n"
2222 " Banana,\n"
2223 " Cantaloupe,\n"
2224 "}\n"
2225 "var x;\n"
2226 "var y;\n"
2227 "var z;\n"
2228 "var w;\n"
2229 "main() {\n"
2230 " x = { Fruit.Apple: Fruit.Apple.index,\n"
2231 " Fruit.Banana: Fruit.Banana.index,\n"
2232 " Fruit.Cantaloupe: Fruit.Cantaloupe.index};\n"
2233 " y = Fruit.Apple;\n"
2234 " z = Fruit.Banana;\n"
2235 " w = Fruit.Cantaloupe;\n"
2236 " return Fruit.Apple.toString();\n"
2237 "}\n";
2238
2239 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2240 EXPECT_VALID(lib);
2241 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2242
2243 const char* kReloadScript =
2244 "enum Fruit {\n"
2245 " Apple,\n"
2246 " Banana,\n"
2247 " Cantaloupe,\n"
2248 "}\n"
2249 "var x;\n"
2250 "var y;\n"
2251 "var z;\n"
2252 "var w;\n"
2253 "bool identityCheck(Fruit f, int index) {\n"
2254 " return identical(Fruit.values[index], f);\n"
2255 "}\n"
2256 "main() {\n"
2257 " String r = '';\n"
2258 " x.forEach((key, value) {\n"
2259 " r += '${identityCheck(key, value)} ';\n"
2260 " });\n"
2261 " r += '${x[Fruit.Apple] == Fruit.Apple.index} ';\n"
2262 " r += '${x[Fruit.Banana] == Fruit.Banana.index} ';\n"
2263 " r += '${x[Fruit.Cantaloupe] == Fruit.Cantaloupe.index} ';\n"
2264 " r += '${identical(y, Fruit.values[x[Fruit.Apple]])} ';\n"
2265 " r += '${identical(z, Fruit.values[x[Fruit.Banana]])} ';\n"
2266 " r += '${identical(w, Fruit.values[x[Fruit.Cantaloupe]])} ';\n"
2267 " return r;\n"
2268 "}\n";
2269
2270 lib = TestCase::ReloadTestScript(kReloadScript);
2271 EXPECT_VALID(lib);
2272 EXPECT_STREQ("true true true true true true true true true ",
2273 SimpleInvokeStr(lib, "main"));
2274}
2275
2276TEST_CASE(IsolateReload_EnumShapeChange) {
2277 const char* kScript =
2278 "enum Fruit { Apple, Banana }\n"
2279 "var retained;\n"
2280 "main() {\n"
2281 " retained = Fruit.Apple;\n"
2282 " return retained.toString();\n"
2283 "}\n";
2284
2285 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2286 EXPECT_VALID(lib);
2287 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2288
2289 const char* kReloadScript =
2290 "enum Fruit {\n"
2291 " Apple('Apple', 'A'),\n"
2292 " Banana('Banana', 'B');\n"
2293 " const Fruit(this.name, this.initial);\n"
2294 " final String name;\n"
2295 " final String initial;\n"
2296 "}\n"
2297 "var retained;\n"
2298 "main() {\n"
2299 " return retained.initial;\n"
2300 "}\n";
2301
2302 lib = TestCase::ReloadTestScript(kReloadScript);
2303 EXPECT_VALID(lib);
2304 EXPECT_STREQ("A", SimpleInvokeStr(lib, "main"));
2305}
2306
2307TEST_CASE(IsolateReload_EnumShapeChangeAdd) {
2308 const char* kScript =
2309 "enum Fruit { Apple, Banana }\n"
2310 "var retained;\n"
2311 "main() {\n"
2312 " retained = Fruit.Apple;\n"
2313 " return retained.toString();\n"
2314 "}\n";
2315
2316 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2317 EXPECT_VALID(lib);
2318 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2319
2320 const char* kReloadScript =
2321 "enum Fruit {\n"
2322 " Apple('Apple', 'A'),\n"
2323 " Banana('Banana', 'B'),\n"
2324 " Cherry('Cherry', 'C');\n"
2325 " const Fruit(this.name, this.initial);\n"
2326 " final String name;\n"
2327 " final String initial;\n"
2328 "}\n"
2329 "var retained;\n"
2330 "main() {\n"
2331 " return Fruit.Cherry.initial;\n"
2332 "}\n";
2333
2334 lib = TestCase::ReloadTestScript(kReloadScript);
2335 EXPECT_VALID(lib);
2336 EXPECT_STREQ("C", SimpleInvokeStr(lib, "main"));
2337}
2338
2339TEST_CASE(IsolateReload_EnumShapeChangeRemove) {
2340 const char* kScript =
2341 "enum Fruit { Apple, Banana }\n"
2342 "var retained;\n"
2343 "main() {\n"
2344 " retained = Fruit.Banana;\n"
2345 " return retained.toString();\n"
2346 "}\n";
2347
2348 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2349 EXPECT_VALID(lib);
2350 EXPECT_STREQ("Fruit.Banana", SimpleInvokeStr(lib, "main"));
2351
2352 const char* kReloadScript =
2353 "enum Fruit {\n"
2354 " Apple('Apple', 'A');\n"
2355 " const Fruit(this.name, this.initial);\n"
2356 " final String name;\n"
2357 " final String initial;\n"
2358 "}\n"
2359 "var retained;\n"
2360 "main() {\n"
2361 " return retained.toString();\n"
2362 "}\n";
2363
2364 lib = TestCase::ReloadTestScript(kReloadScript);
2365 EXPECT_VALID(lib);
2366 EXPECT_STREQ("Fruit.Deleted enum value from Fruit",
2367 SimpleInvokeStr(lib, "main"));
2368}
2369
2370TEST_CASE(IsolateReload_EnumReferentShapeChangeAdd) {
2371 const char* kScript =
2372 "class Box {\n"
2373 " final x;\n"
2374 " const Box(this.x);\n"
2375 "}\n"
2376 "enum Fruit {\n"
2377 " Apple('Apple', const Box('A')),\n"
2378 " Banana('Banana', const Box('B')),\n"
2379 " Cherry('Cherry', const Box('C')),\n"
2380 " Durian('Durian', const Box('D')),\n"
2381 " Elderberry('Elderberry', const Box('E')),\n"
2382 " Fig('Fig', const Box('F')),\n"
2383 " Grape('Grape', const Box('G')),\n"
2384 " Huckleberry('Huckleberry', const Box('H')),\n"
2385 " Jackfruit('Jackfruit', const Box('J'));\n"
2386 " const Fruit(this.name, this.initial);\n"
2387 " final String name;\n"
2388 " final Box initial;\n"
2389 "}\n"
2390 "var retained;\n"
2391 "main() {\n"
2392 " retained = Fruit.Apple;\n"
2393 " return retained.toString();\n"
2394 "}\n";
2395
2396 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2397 EXPECT_VALID(lib);
2398 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2399
2400 const char* kReloadScript =
2401 "class Box {\n"
2402 " final x;\n"
2403 " final y;\n"
2404 " final z;\n"
2405 " const Box(this.x, this.y, this.z);\n"
2406 "}\n"
2407 "enum Fruit {\n"
2408 " Apple('Apple', const Box('A', 0, 0)),\n"
2409 " Banana('Banana', const Box('B', 0, 0)),\n"
2410 " Cherry('Cherry', const Box('C', 0, 0)),\n"
2411 " Durian('Durian', const Box('D', 0, 0)),\n"
2412 " Elderberry('Elderberry', const Box('E', 0, 0)),\n"
2413 " Fig('Fig', const Box('F', 0, 0)),\n"
2414 " Grape('Grape', const Box('G', 0, 0)),\n"
2415 " Huckleberry('Huckleberry', const Box('H', 0, 0)),\n"
2416 " Jackfruit('Jackfruit', const Box('J', 0, 0)),\n"
2417 " Lemon('Lemon', const Box('L', 0, 0));\n"
2418 " const Fruit(this.name, this.initial);\n"
2419 " final String name;\n"
2420 " final Box initial;\n"
2421 "}\n"
2422 "var retained;\n"
2423 "main() {\n"
2424 " return retained.toString();\n"
2425 "}\n";
2426
2427 lib = TestCase::ReloadTestScript(kReloadScript);
2428 EXPECT_VALID(lib);
2429 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2430}
2431
2432TEST_CASE(IsolateReload_ConstantIdentical) {
2433 const char* kScript =
2434 "class Fruit {\n"
2435 " final String name;\n"
2436 " const Fruit(this.name);\n"
2437 " String toString() => name;\n"
2438 "}\n"
2439 "var x;\n"
2440 "main() {\n"
2441 " x = const Fruit('Pear');\n"
2442 " return x.toString();\n"
2443 "}\n";
2444
2445 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
2446 EXPECT_VALID(lib);
2447 EXPECT_STREQ("Pear", SimpleInvokeStr(lib, "main"));
2448
2449 const char* kReloadScript =
2450 "class Fruit {\n"
2451 " final String name;\n"
2452 " const Fruit(this.name);\n"
2453 " String toString() => name;\n"
2454 "}\n"
2455 "var x;\n"
2456 "main() {\n"
2457 " if (identical(x, const Fruit('Pear'))) {\n"
2458 " return 'yes';\n"
2459 " } else {\n"
2460 " return 'no';\n"
2461 " }\n"
2462 "}\n";
2463
2464 lib = TestCase::ReloadTestScript(kReloadScript);
2465 EXPECT_VALID(lib);
2466 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
2467}
2468
2469TEST_CASE(IsolateReload_CallDeleted_TopLevelFunction) {
2470 const char* kScript =
2471 "deleted() { return 'hello'; }\n"
2472 "var retained;\n"
2473 "main() {\n"
2474 " retained = () => deleted();\n"
2475 " return retained();\n"
2476 "}\n";
2477
2478 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2479 EXPECT_VALID(lib);
2480 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2481
2482 const char* kReloadScript =
2483 "var retained;\n"
2484 "main() {\n"
2485 " try {\n"
2486 " return retained();\n"
2487 " } catch (e) {\n"
2488 " return e.toString();\n"
2489 " }\n"
2490 "}\n";
2491
2492 lib = TestCase::ReloadTestScript(kReloadScript);
2493 EXPECT_VALID(lib);
2494 const char* result = SimpleInvokeStr(lib, "main");
2495 EXPECT_SUBSTRING("NoSuchMethodError", result);
2496 EXPECT_SUBSTRING("deleted", result);
2497}
2498
2499TEST_CASE(IsolateReload_CallDeleted_TopLevelFunctionArityChange) {
2500 const char* kScript =
2501 "deleted() { return 'hello'; }\n"
2502 "var retained;\n"
2503 "main() {\n"
2504 " retained = () => deleted();\n"
2505 " return retained();\n"
2506 "}\n";
2507
2508 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2509 EXPECT_VALID(lib);
2510 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2511
2512 const char* kReloadScript =
2513 "deleted(newParameter) { return 'hello'; }\n"
2514 "var retained;\n"
2515 "main() {\n"
2516 " try {\n"
2517 " return retained();\n"
2518 " } catch (e) {\n"
2519 " return e.toString();\n"
2520 " }\n"
2521 "}\n";
2522
2523 lib = TestCase::ReloadTestScript(kReloadScript);
2524 EXPECT_VALID(lib);
2525 const char* result = SimpleInvokeStr(lib, "main");
2526 EXPECT_SUBSTRING("NoSuchMethodError", result);
2527 EXPECT_SUBSTRING("deleted", result);
2528}
2529
2530TEST_CASE(IsolateReload_CallDeleted_TopLevelAddTypeArguments) {
2531 const char* kScript =
2532 "deleted() { return 'hello'; }\n"
2533 "var retained;\n"
2534 "main() {\n"
2535 " retained = () => deleted();\n"
2536 " return retained();\n"
2537 "}\n";
2538
2539 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2540 EXPECT_VALID(lib);
2541 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2542
2543 const char* kReloadScript =
2544 "deleted<A, B, C>() { return 'hello'; }\n"
2545 "var retained;\n"
2546 "main() {\n"
2547 " try {\n"
2548 " return retained();\n"
2549 " } catch (e) {\n"
2550 " return e.toString();\n"
2551 " }\n"
2552 "}\n";
2553
2554 lib = TestCase::ReloadTestScript(kReloadScript);
2555 EXPECT_VALID(lib);
2556 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2557}
2558
2559TEST_CASE(IsolateReload_CallDeleted_TopLevelRemoveTypeArguments) {
2560 const char* kScript =
2561 "deleted<A, B, C>() { return 'hello'; }\n"
2562 "var retained;\n"
2563 "main() {\n"
2564 " retained = () => deleted<int, int, int>();\n"
2565 " return retained();\n"
2566 "}\n";
2567
2568 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2569 EXPECT_VALID(lib);
2570 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2571
2572 const char* kReloadScript =
2573 "deleted() { return 'hello'; }\n"
2574 "var retained;\n"
2575 "main() {\n"
2576 " try {\n"
2577 " return retained();\n"
2578 " } catch (e) {\n"
2579 " return e.toString();\n"
2580 " }\n"
2581 "}\n";
2582
2583 lib = TestCase::ReloadTestScript(kReloadScript);
2584 EXPECT_VALID(lib);
2585 const char* result = SimpleInvokeStr(lib, "main");
2586 EXPECT_SUBSTRING("NoSuchMethodError", result);
2587 EXPECT_SUBSTRING("deleted", result);
2588}
2589
2590TEST_CASE(IsolateReload_CallDeleted_TopLevelMissingPassingTypeArguments) {
2591 const char* kScript =
2592 "deleted<A, B, C>() { return 'hello'; }\n"
2593 "var retained;\n"
2594 "main() {\n"
2595 " retained = () => deleted<int, int, int>();\n"
2596 " return retained();\n"
2597 "}\n";
2598
2599 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2600 EXPECT_VALID(lib);
2601 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2602
2603 const char* kReloadScript =
2604 "var retained;\n"
2605 "main() {\n"
2606 " try {\n"
2607 " return retained();\n"
2608 " } catch (e) {\n"
2609 " return e.toString();\n"
2610 " }\n"
2611 "}\n";
2612
2613 lib = TestCase::ReloadTestScript(kReloadScript);
2614 EXPECT_VALID(lib);
2615 const char* result = SimpleInvokeStr(lib, "main");
2616 EXPECT_SUBSTRING("NoSuchMethodError", result);
2617 EXPECT_SUBSTRING("deleted", result);
2618}
2619
2620TEST_CASE(IsolateReload_CallDeleted_TopLevelFunctionEvaluationOrder) {
2621 const char* kScript =
2622 "first(flag) { if (flag) throw 'first!'; }\n"
2623 "deleted(_) { return 'hello'; }\n"
2624 "var retained;\n"
2625 "main() {\n"
2626 " retained = (bool flag) => deleted(first(flag));\n"
2627 " return retained(false);\n"
2628 "}\n";
2629
2630 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2631 EXPECT_VALID(lib);
2632 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2633
2634 const char* kReloadScript =
2635 "first(flag) { if (flag) throw 'first!'; }\n"
2636 "var retained;\n"
2637 "main() {\n"
2638 " try {\n"
2639 " return retained(true);\n"
2640 " } catch (e) {\n"
2641 " return e.toString();\n"
2642 " }\n"
2643 "}\n";
2644
2645 lib = TestCase::ReloadTestScript(kReloadScript);
2646 EXPECT_VALID(lib);
2647 const char* result = SimpleInvokeStr(lib, "main");
2648 EXPECT_STREQ("first!", result); // Not NoSuchMethodError
2649}
2650
2651TEST_CASE(IsolateReload_CallDeleted_TopLevelFunctionLibraryDeleted) {
2652 // clang-format off
2653 Dart_SourceFile sourcefiles[] = {
2654 {
2655 "file:///test-app.dart",
2656
2657 "import 'test-lib.dart';\n"
2658 "var retained;\n"
2659 "main() {\n"
2660 " retained = () => deleted();\n"
2661 " return retained();\n"
2662 "}\n",
2663 },
2664 {
2665 "file:///test-lib.dart",
2666
2667 "deleted() { return 'hello'; }\n",
2668 },
2669 };
2670 // clang-format on
2671
2673 sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
2674 NULL /* resolver */, true /* finalize */, true /* incrementally */);
2675 EXPECT_VALID(lib);
2676 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2677
2678 // clang-format off
2679 Dart_SourceFile updated_sourcefiles[] = {
2680 {
2681 "file:///test-app.dart",
2682
2683 "var retained;\n"
2684 "main() {\n"
2685 " try {\n"
2686 " return retained();\n"
2687 " } catch (e) {\n"
2688 " return e.toString();\n"
2689 " }\n"
2690 "}\n",
2691 },
2692 };
2693 // clang-format on
2694
2695 const uint8_t* kernel_buffer = NULL;
2696 intptr_t kernel_buffer_size = 0;
2698 "file:///test-app.dart",
2699 sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
2700 updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
2701 true /* incrementally */);
2702 EXPECT(error == NULL);
2703 EXPECT_NOTNULL(kernel_buffer);
2704 lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
2705 EXPECT_VALID(lib);
2706 const char* result = SimpleInvokeStr(lib, "main");
2707 // What actually happens because we don't re-search imported libraries.
2708 EXPECT_STREQ(result, "hello");
2709
2710 // What should happen and what did happen with the old VM frontend:
2711 // EXPECT_SUBSTRING("NoSuchMethodError", result);
2712 // EXPECT_SUBSTRING("deleted", result);
2713}
2714
2715TEST_CASE(IsolateReload_CallDeleted_TopLevelGetter) {
2716 const char* kScript =
2717 "get deleted { return 'hello'; }\n"
2718 "var retained;\n"
2719 "main() {\n"
2720 " retained = () => deleted;\n"
2721 " return retained();\n"
2722 "}\n";
2723
2724 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2725 EXPECT_VALID(lib);
2726 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2727
2728 const char* kReloadScript =
2729 "var retained;\n"
2730 "main() {\n"
2731 " try {\n"
2732 " return retained();\n"
2733 " } catch (e) {\n"
2734 " return e.toString();\n"
2735 " }\n"
2736 "}\n";
2737
2738 lib = TestCase::ReloadTestScript(kReloadScript);
2739 EXPECT_VALID(lib);
2740 const char* result = SimpleInvokeStr(lib, "main");
2741 EXPECT_SUBSTRING("NoSuchMethodError", result);
2742 EXPECT_SUBSTRING("deleted", result);
2743}
2744
2745TEST_CASE(IsolateReload_CallDeleted_TopLevelSetter) {
2746 const char* kScript =
2747 "set deleted(x) {}\n"
2748 "var retained;\n"
2749 "main() {\n"
2750 " retained = () => deleted = 'hello';\n"
2751 " return retained();\n"
2752 "}\n";
2753
2754 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2755 EXPECT_VALID(lib);
2756 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2757
2758 const char* kReloadScript =
2759 "var retained;\n"
2760 "main() {\n"
2761 " try {\n"
2762 " return retained();\n"
2763 " } catch (e) {\n"
2764 " return e.toString();\n"
2765 " }\n"
2766 "}\n";
2767
2768 lib = TestCase::ReloadTestScript(kReloadScript);
2769 EXPECT_VALID(lib);
2770 const char* result = SimpleInvokeStr(lib, "main");
2771 EXPECT_SUBSTRING("NoSuchMethodError", result);
2772 EXPECT_SUBSTRING("deleted", result);
2773}
2774
2775TEST_CASE(IsolateReload_CallDeleted_TopLevelSetterEvaluationOrder) {
2776 const char* kScript =
2777 "first(flag) { if (flag) throw 'first!'; return 'hello'; }\n"
2778 "set deleted(x) {}\n"
2779 "var retained;\n"
2780 "main() {\n"
2781 " retained = (bool flag) => deleted = first(flag);\n"
2782 " return retained(false);\n"
2783 "}\n";
2784
2785 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2786 EXPECT_VALID(lib);
2787 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2788
2789 const char* kReloadScript =
2790 "first(flag) { if (flag) throw 'first!'; return 'hello'; }\n"
2791 "var retained;\n"
2792 "main() {\n"
2793 " try {\n"
2794 " return retained(true);\n"
2795 " } catch (e) {\n"
2796 " return e.toString();\n"
2797 " }\n"
2798 "}\n";
2799
2800 lib = TestCase::ReloadTestScript(kReloadScript);
2801 EXPECT_VALID(lib);
2802 const char* result = SimpleInvokeStr(lib, "main");
2803 EXPECT_STREQ("first!", result); // Not NoSuchMethodError
2804}
2805
2806TEST_CASE(IsolateReload_CallDeleted_ClassFunction) {
2807 const char* kScript =
2808 "class C { static deleted() { return 'hello'; } }\n"
2809 "var retained;\n"
2810 "main() {\n"
2811 " retained = () => C.deleted();\n"
2812 " return retained();\n"
2813 "}\n";
2814
2815 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2816 EXPECT_VALID(lib);
2817 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2818
2819 const char* kReloadScript =
2820 "var retained;\n"
2821 "main() {\n"
2822 " try {\n"
2823 " return retained();\n"
2824 " } catch (e) {\n"
2825 " return e.toString();\n"
2826 " }\n"
2827 "}\n";
2828
2829 lib = TestCase::ReloadTestScript(kReloadScript);
2830 EXPECT_VALID(lib);
2831 const char* result = SimpleInvokeStr(lib, "main");
2832 EXPECT_SUBSTRING("NoSuchMethodError", result);
2833 EXPECT_SUBSTRING("deleted", result);
2834}
2835
2836TEST_CASE(IsolateReload_CallDeleted_ClassFunctionArityChange) {
2837 const char* kScript =
2838 "class C { static deleted() { return 'hello'; } }\n"
2839 "var retained;\n"
2840 "main() {\n"
2841 " retained = () => C.deleted();\n"
2842 " return retained();\n"
2843 "}\n";
2844
2845 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2846 EXPECT_VALID(lib);
2847 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2848
2849 const char* kReloadScript =
2850 "class C { static deleted(newParameter) { return 'hello'; } }\n"
2851 "var retained;\n"
2852 "main() {\n"
2853 " try {\n"
2854 " return retained();\n"
2855 " } catch (e) {\n"
2856 " return e.toString();\n"
2857 " }\n"
2858 "}\n";
2859
2860 lib = TestCase::ReloadTestScript(kReloadScript);
2861 EXPECT_VALID(lib);
2862 const char* result = SimpleInvokeStr(lib, "main");
2863 EXPECT_SUBSTRING("NoSuchMethodError", result);
2864 EXPECT_SUBSTRING("deleted", result);
2865}
2866
2867TEST_CASE(IsolateReload_CallDeleted_ClassFunctionEvaluationOrder) {
2868 const char* kScript =
2869 "first(flag) { if (flag) throw 'first!'; }\n"
2870 "class C { static deleted(_) { return 'hello'; } }\n"
2871 "var retained;\n"
2872 "main() {\n"
2873 " retained = (bool flag) => C.deleted(first(flag));\n"
2874 " return retained(false);\n"
2875 "}\n";
2876
2877 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2878 EXPECT_VALID(lib);
2879 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2880
2881 const char* kReloadScript =
2882 "first(flag) { if (flag) throw 'first!'; }\n"
2883 "class C { }\n"
2884 "var retained;\n"
2885 "main() {\n"
2886 " try {\n"
2887 " return retained(true);\n"
2888 " } catch (e) {\n"
2889 " return e.toString();\n"
2890 " }\n"
2891 "}\n";
2892
2893 lib = TestCase::ReloadTestScript(kReloadScript);
2894 EXPECT_VALID(lib);
2895 const char* result = SimpleInvokeStr(lib, "main");
2896 EXPECT_STREQ("first!", result); // Not NoSuchMethodError
2897}
2898
2899TEST_CASE(IsolateReload_CallDeleted_ClassGetter) {
2900 const char* kScript =
2901 "class C { static get deleted { return 'hello'; } }\n"
2902 "var retained;\n"
2903 "main() {\n"
2904 " retained = () => C.deleted;\n"
2905 " return retained();\n"
2906 "}\n";
2907
2908 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2909 EXPECT_VALID(lib);
2910 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2911
2912 const char* kReloadScript =
2913 "var retained;\n"
2914 "main() {\n"
2915 " try {\n"
2916 " return retained();\n"
2917 " } catch (e) {\n"
2918 " return e.toString();\n"
2919 " }\n"
2920 "}\n";
2921
2922 lib = TestCase::ReloadTestScript(kReloadScript);
2923 EXPECT_VALID(lib);
2924 const char* result = SimpleInvokeStr(lib, "main");
2925 EXPECT_SUBSTRING("NoSuchMethodError", result);
2926 EXPECT_SUBSTRING("deleted", result);
2927}
2928
2929TEST_CASE(IsolateReload_CallDeleted_ClassSetter) {
2930 const char* kScript =
2931 "class C { static set deleted(x) {}}\n"
2932 "var retained;\n"
2933 "main() {\n"
2934 " retained = () => C.deleted = 'hello';\n"
2935 " return retained();\n"
2936 "}\n";
2937
2938 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2939 EXPECT_VALID(lib);
2940 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2941
2942 const char* kReloadScript =
2943 "var retained;\n"
2944 "main() {\n"
2945 " try {\n"
2946 " return retained();\n"
2947 " } catch (e) {\n"
2948 " return e.toString();\n"
2949 " }\n"
2950 "}\n";
2951
2952 lib = TestCase::ReloadTestScript(kReloadScript);
2953 EXPECT_VALID(lib);
2954 const char* result = SimpleInvokeStr(lib, "main");
2955 EXPECT_SUBSTRING("NoSuchMethodError", result);
2956 EXPECT_SUBSTRING("deleted", result);
2957}
2958
2959TEST_CASE(IsolateReload_CallDeleted_ClassSetterEvaluationOrder) {
2960 const char* kScript =
2961 "first(flag) { if (flag) throw 'first!'; return 'hello'; }\n"
2962 "class C { static set deleted(x) {}}\n"
2963 "var retained;\n"
2964 "main() {\n"
2965 " retained = (bool flag) => C.deleted = first(flag);\n"
2966 " return retained(false);\n"
2967 "}\n";
2968
2969 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2970 EXPECT_VALID(lib);
2971 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
2972
2973 const char* kReloadScript =
2974 "first(flag) { if (flag) throw 'first!'; return 'hello'; }\n"
2975 "var retained;\n"
2976 "main() {\n"
2977 " try {\n"
2978 " return retained(true);\n"
2979 " } catch (e) {\n"
2980 " return e.toString();\n"
2981 " }\n"
2982 "}\n";
2983
2984 lib = TestCase::ReloadTestScript(kReloadScript);
2985 EXPECT_VALID(lib);
2986 const char* result = SimpleInvokeStr(lib, "main");
2987 EXPECT_STREQ("first!", result);
2988}
2989
2990TEST_CASE(IsolateReload_CallDeleted_ClassGenerativeConstructor) {
2991 const char* kScript =
2992 "class C { C.deleted(); }\n"
2993 "var retained;\n"
2994 "main() {\n"
2995 " retained = () => C.deleted().toString();\n"
2996 " return retained();\n"
2997 "}\n";
2998
2999 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3000 EXPECT_VALID(lib);
3001 EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
3002
3003 const char* kReloadScript =
3004 "class C {}\n"
3005 "var retained;\n"
3006 "main() {\n"
3007 " try {\n"
3008 " return retained();\n"
3009 " } catch (e) {\n"
3010 " return e.toString();\n"
3011 " }\n"
3012 "}\n";
3013
3014 lib = TestCase::ReloadTestScript(kReloadScript);
3015 EXPECT_VALID(lib);
3016 const char* result = SimpleInvokeStr(lib, "main");
3017 EXPECT_SUBSTRING("NoSuchMethodError", result);
3018 EXPECT_SUBSTRING("deleted", result);
3019}
3020
3021TEST_CASE(IsolateReload_CallDeleted_ClassGenerativeConstructorArityChange) {
3022 const char* kScript =
3023 "class C { C.deleted(); }\n"
3024 "var retained;\n"
3025 "main() {\n"
3026 " retained = () => C.deleted().toString();\n"
3027 " return retained();\n"
3028 "}\n";
3029
3030 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3031 EXPECT_VALID(lib);
3032 EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
3033
3034 const char* kReloadScript =
3035 "class C { C.deleted(newParameter); }\n"
3036 "var retained;\n"
3037 "main() {\n"
3038 " try {\n"
3039 " return retained();\n"
3040 " } catch (e) {\n"
3041 " return e.toString();\n"
3042 " }\n"
3043 "}\n";
3044
3045 lib = TestCase::ReloadTestScript(kReloadScript);
3046 EXPECT_VALID(lib);
3047 const char* result = SimpleInvokeStr(lib, "main");
3048 EXPECT_SUBSTRING("NoSuchMethodError", result);
3049 EXPECT_SUBSTRING("deleted", result);
3050}
3051
3052TEST_CASE(IsolateReload_CallDeleted_ClassGenerativeConstructorClassDeleted) {
3053 const char* kScript =
3054 "class C { C.deleted(); }\n"
3055 "var retained;\n"
3056 "main() {\n"
3057 " retained = () => C.deleted().toString();\n"
3058 " return retained();\n"
3059 "}\n";
3060
3061 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3062 EXPECT_VALID(lib);
3063 EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
3064
3065 const char* kReloadScript =
3066 "var retained;\n"
3067 "main() {\n"
3068 " try {\n"
3069 " return retained();\n"
3070 " } catch (e) {\n"
3071 " return e.toString();\n"
3072 " }\n"
3073 "}\n";
3074
3075 lib = TestCase::ReloadTestScript(kReloadScript);
3076 EXPECT_VALID(lib);
3077 const char* result = SimpleInvokeStr(lib, "main");
3078 EXPECT_SUBSTRING("NoSuchMethodError", result);
3079 EXPECT_SUBSTRING("deleted", result);
3080}
3081
3082TEST_CASE(IsolateReload_CallDeleted_ClassFactoryConstructor) {
3083 const char* kScript =
3084 "class C { factory C.deleted() => new C(); C(); }\n"
3085 "var retained;\n"
3086 "main() {\n"
3087 " retained = () => C.deleted().toString();\n"
3088 " return retained();\n"
3089 "}\n";
3090
3091 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3092 EXPECT_VALID(lib);
3093 EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
3094
3095 const char* kReloadScript =
3096 "class C {}\n"
3097 "var retained;\n"
3098 "main() {\n"
3099 " try {\n"
3100 " return retained();\n"
3101 " } catch (e) {\n"
3102 " return e.toString();\n"
3103 " }\n"
3104 "}\n";
3105
3106 lib = TestCase::ReloadTestScript(kReloadScript);
3107 EXPECT_VALID(lib);
3108 const char* result = SimpleInvokeStr(lib, "main");
3109 EXPECT_SUBSTRING("NoSuchMethodError", result);
3110 EXPECT_SUBSTRING("deleted", result);
3111}
3112
3113TEST_CASE(IsolateReload_CallDeleted_ClassFactoryConstructorArityChange) {
3114 const char* kScript =
3115 "class C { factory C.deleted() => new C(); C(); }\n"
3116 "var retained;\n"
3117 "main() {\n"
3118 " retained = () => C.deleted().toString();\n"
3119 " return retained();\n"
3120 "}\n";
3121
3122 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3123 EXPECT_VALID(lib);
3124 EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
3125
3126 const char* kReloadScript =
3127 "class C { factory C.deleted(newParameter) => new C(); C(); }\n"
3128 "var retained;\n"
3129 "main() {\n"
3130 " try {\n"
3131 " return retained();\n"
3132 " } catch (e) {\n"
3133 " return e.toString();\n"
3134 " }\n"
3135 "}\n";
3136
3137 lib = TestCase::ReloadTestScript(kReloadScript);
3138 EXPECT_VALID(lib);
3139 const char* result = SimpleInvokeStr(lib, "main");
3140 EXPECT_SUBSTRING("NoSuchMethodError", result);
3141 EXPECT_SUBSTRING("deleted", result);
3142}
3143
3144TEST_CASE(IsolateReload_CallDeleted_ClassFactoryConstructorClassDeleted) {
3145 const char* kScript =
3146 "class C { factory C.deleted() => new C(); C(); }\n"
3147 "var retained;\n"
3148 "main() {\n"
3149 " retained = () => C.deleted().toString();\n"
3150 " return retained();\n"
3151 "}\n";
3152
3153 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3154 EXPECT_VALID(lib);
3155 EXPECT_STREQ("Instance of \'C\'", SimpleInvokeStr(lib, "main"));
3156
3157 const char* kReloadScript =
3158 "var retained;\n"
3159 "main() {\n"
3160 " try {\n"
3161 " return retained();\n"
3162 " } catch (e) {\n"
3163 " return e.toString();\n"
3164 " }\n"
3165 "}\n";
3166
3167 lib = TestCase::ReloadTestScript(kReloadScript);
3168 EXPECT_VALID(lib);
3169 const char* result = SimpleInvokeStr(lib, "main");
3170 EXPECT_SUBSTRING("NoSuchMethodError", result);
3171 EXPECT_SUBSTRING("deleted", result);
3172}
3173
3174TEST_CASE(IsolateReload_CallDeleted_SuperFunction) {
3175 const char* kScript =
3176 "class C { deleted() { return 'hello'; } }\n"
3177 "class D extends C { curry() => () => super.deleted(); }\n"
3178 "var retained;\n"
3179 "main() {\n"
3180 " retained = new D().curry();\n"
3181 " return retained();\n"
3182 "}\n";
3183
3184 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3185 EXPECT_VALID(lib);
3186 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
3187
3188 const char* kReloadScript =
3189 "class C {}\n"
3190 "class D extends C {}\n"
3191 "var retained;\n"
3192 "main() {\n"
3193 " try {\n"
3194 " return retained();\n"
3195 " } catch (e) {\n"
3196 " return e.toString();\n"
3197 " }\n"
3198 "}\n";
3199
3200 lib = TestCase::ReloadTestScript(kReloadScript);
3201 EXPECT_VALID(lib);
3202 const char* result = SimpleInvokeStr(lib, "main");
3203 EXPECT_SUBSTRING("NoSuchMethodError", result);
3204 EXPECT_SUBSTRING("deleted", result);
3205}
3206
3207TEST_CASE(IsolateReload_CallDeleted_SuperFunctionArityChange) {
3208 const char* kScript =
3209 "class C { deleted() { return 'hello'; } }\n"
3210 "class D extends C { curry() => () => super.deleted(); }\n"
3211 "var retained;\n"
3212 "main() {\n"
3213 " retained = new D().curry();\n"
3214 " return retained();\n"
3215 "}\n";
3216
3217 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3218 EXPECT_VALID(lib);
3219 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
3220
3221 const char* kReloadScript =
3222 "class C { deleted(newParameter) { return 'hello'; } }\n"
3223 "class D extends C {}\n"
3224 "var retained;\n"
3225 "main() {\n"
3226 " try {\n"
3227 " return retained();\n"
3228 " } catch (e) {\n"
3229 " return e.toString();\n"
3230 " }\n"
3231 "}\n";
3232
3233 lib = TestCase::ReloadTestScript(kReloadScript);
3234 EXPECT_VALID(lib);
3235 const char* result = SimpleInvokeStr(lib, "main");
3236 EXPECT_SUBSTRING("NoSuchMethodError", result);
3237 EXPECT_SUBSTRING("deleted", result);
3238}
3239
3240TEST_CASE(IsolateReload_CallDeleted_SuperGetter) {
3241 const char* kScript =
3242 "class C { get deleted { return 'hello'; } }\n"
3243 "class D extends C { curry() => () => super.deleted; }\n"
3244 "var retained;\n"
3245 "main() {\n"
3246 " retained = new D().curry();\n"
3247 " return retained();\n"
3248 "}\n";
3249
3250 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3251 EXPECT_VALID(lib);
3252 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
3253
3254 const char* kReloadScript =
3255 "class C {}\n"
3256 "class D extends C {}\n"
3257 "var retained;\n"
3258 "main() {\n"
3259 " try {\n"
3260 " return retained();\n"
3261 " } catch (e) {\n"
3262 " return e.toString();\n"
3263 " }\n"
3264 "}\n";
3265
3266 lib = TestCase::ReloadTestScript(kReloadScript);
3267 EXPECT_VALID(lib);
3268 const char* result = SimpleInvokeStr(lib, "main");
3269 EXPECT_SUBSTRING("NoSuchMethodError", result);
3270 EXPECT_SUBSTRING("deleted", result);
3271}
3272
3273TEST_CASE(IsolateReload_CallDeleted_SuperSetter) {
3274 const char* kScript =
3275 "class C { set deleted(x) {} }\n"
3276 "class D extends C { curry() => () => super.deleted = 'hello'; }\n"
3277 "var retained;\n"
3278 "main() {\n"
3279 " retained = new D().curry();\n"
3280 " return retained();\n"
3281 "}\n";
3282
3283 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3284 EXPECT_VALID(lib);
3285 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
3286
3287 const char* kReloadScript =
3288 "class C {}\n"
3289 "class D extends C {}\n"
3290 "var retained;\n"
3291 "main() {\n"
3292 " try {\n"
3293 " return retained();\n"
3294 " } catch (e) {\n"
3295 " return e.toString();\n"
3296 " }\n"
3297 "}\n";
3298
3299 lib = TestCase::ReloadTestScript(kReloadScript);
3300 EXPECT_VALID(lib);
3301 const char* result = SimpleInvokeStr(lib, "main");
3302 EXPECT_SUBSTRING("NoSuchMethodError", result);
3303 EXPECT_SUBSTRING("deleted", result);
3304}
3305
3306TEST_CASE(IsolateReload_CallDeleted_SuperFieldGetter) {
3307 const char* kScript =
3308 "class C { var deleted = 'hello'; }\n"
3309 "class D extends C { curry() => () => super.deleted; }\n"
3310 "var retained;\n"
3311 "main() {\n"
3312 " retained = new D().curry();\n"
3313 " return retained();\n"
3314 "}\n";
3315
3316 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3317 EXPECT_VALID(lib);
3318 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
3319
3320 const char* kReloadScript =
3321 "class C {}\n"
3322 "class D extends C {}\n"
3323 "var retained;\n"
3324 "main() {\n"
3325 " try {\n"
3326 " return retained();\n"
3327 " } catch (e) {\n"
3328 " return e.toString();\n"
3329 " }\n"
3330 "}\n";
3331
3332 lib = TestCase::ReloadTestScript(kReloadScript);
3333 EXPECT_VALID(lib);
3334 const char* result = SimpleInvokeStr(lib, "main");
3335 EXPECT_SUBSTRING("NoSuchMethodError", result);
3336 EXPECT_SUBSTRING("deleted", result);
3337}
3338
3339TEST_CASE(IsolateReload_CallDeleted_SuperFieldSetter) {
3340 const char* kScript =
3341 "class C { var deleted; }\n"
3342 "class D extends C { curry() => () => super.deleted = 'hello'; }\n"
3343 "var retained;\n"
3344 "main() {\n"
3345 " retained = new D().curry();\n"
3346 " return retained();\n"
3347 "}\n";
3348
3349 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3350 EXPECT_VALID(lib);
3351 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
3352
3353 const char* kReloadScript =
3354 "class C {}\n"
3355 "class D extends C {}\n"
3356 "var retained;\n"
3357 "main() {\n"
3358 " try {\n"
3359 " return retained();\n"
3360 " } catch (e) {\n"
3361 " return e.toString();\n"
3362 " }\n"
3363 "}\n";
3364
3365 lib = TestCase::ReloadTestScript(kReloadScript);
3366 EXPECT_VALID(lib);
3367 const char* result = SimpleInvokeStr(lib, "main");
3368 EXPECT_SUBSTRING("NoSuchMethodError", result);
3369 EXPECT_SUBSTRING("deleted", result);
3370}
3371
3372TEST_CASE(IsolateReload_EnumValuesToString) {
3373 const char* kScript =
3374 "enum Fruit {\n"
3375 " Apple,\n"
3376 " Banana,\n"
3377 "}\n"
3378 "var x;\n"
3379 "main() {\n"
3380 " String r = '';\n"
3381 " r += Fruit.Apple.toString();\n"
3382 " r += ' ';\n"
3383 " r += Fruit.Banana.toString();\n"
3384 " return r;\n"
3385 "}\n";
3386
3387 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3388 EXPECT_VALID(lib);
3389 EXPECT_STREQ("Fruit.Apple Fruit.Banana", SimpleInvokeStr(lib, "main"));
3390
3391 // Insert 'Cantaloupe'.
3392
3393 const char* kReloadScript =
3394 "enum Fruit {\n"
3395 " Apple,\n"
3396 " Cantaloupe,\n"
3397 " Banana\n"
3398 "}\n"
3399 "var x;\n"
3400 "main() {\n"
3401 " String r = '';\n"
3402 " r += Fruit.Apple.toString();\n"
3403 " r += ' ';\n"
3404 " r += Fruit.Cantaloupe.toString();\n"
3405 " r += ' ';\n"
3406 " r += Fruit.Banana.toString();\n"
3407 " return r;\n"
3408 "}\n";
3409
3410 lib = TestCase::ReloadTestScript(kReloadScript);
3411 EXPECT_VALID(lib);
3412 EXPECT_STREQ("Fruit.Apple Fruit.Cantaloupe Fruit.Banana",
3413 SimpleInvokeStr(lib, "main"));
3414}
3415
3416ISOLATE_UNIT_TEST_CASE(IsolateReload_DirectSubclasses_Success) {
3417 Object& new_subclass = Object::Handle();
3419
3420 // Lookup the Stopwatch class by name from the dart core library.
3421 ObjectStore* object_store = IsolateGroup::Current()->object_store();
3422 const Library& core_lib = Library::Handle(object_store->core_library());
3423 name = String::New("Stopwatch");
3424 const Class& stopwatch_cls = Class::Handle(core_lib.LookupClass(name));
3425
3426 // Keep track of how many subclasses an Stopwatch has.
3427 auto& subclasses =
3429 intptr_t saved_subclass_count = subclasses.IsNull() ? 0 : subclasses.Length();
3430
3431 const char* kScript =
3432 "class AStopwatch extends Stopwatch {\n"
3433 "}\n"
3434 "main() {\n"
3435 " new AStopwatch();\n" // Force finalization.
3436 " return 1;\n"
3437 "}\n";
3438
3439 {
3440 TransitionVMToNative transition(thread);
3441 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3442 EXPECT_VALID(lib);
3443 EXPECT_EQ(1, SimpleInvoke(lib, "main"));
3444 }
3445
3446 // Stopwatch has one non-core subclass.
3447 subclasses = stopwatch_cls.direct_subclasses_unsafe();
3448 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
3449
3450 // The new subclass is named AStopwatch.
3451 new_subclass = subclasses.At(subclasses.Length() - 1);
3452 name = Class::Cast(new_subclass).Name();
3453 EXPECT_STREQ("AStopwatch", name.ToCString());
3454
3455 const char* kReloadScript =
3456 "class AStopwatch {\n"
3457 "}\n"
3458 "class BStopwatch extends Stopwatch {\n"
3459 "}\n"
3460 "main() {\n"
3461 " new AStopwatch();\n" // Force finalization.
3462 " new BStopwatch();\n" // Force finalization.
3463 " return 2;\n"
3464 "}\n";
3465
3466 {
3467 TransitionVMToNative transition(thread);
3468 Dart_Handle lib = TestCase::ReloadTestScript(kReloadScript);
3469 EXPECT_VALID(lib);
3470 EXPECT_EQ(2, SimpleInvoke(lib, "main"));
3471 }
3472
3473 // Stopwatch still has only one non-core subclass (AStopwatch is gone).
3474 subclasses = stopwatch_cls.direct_subclasses_unsafe();
3475 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
3476
3477 // The new subclass is named BStopwatch.
3478 new_subclass = subclasses.At(subclasses.Length() - 1);
3479 name = Class::Cast(new_subclass).Name();
3480 EXPECT_STREQ("BStopwatch", name.ToCString());
3481}
3482
3483ISOLATE_UNIT_TEST_CASE(IsolateReload_DirectSubclasses_GhostSubclass) {
3484 Object& new_subclass = Object::Handle();
3486
3487 // Lookup the Stopwatch class by name from the dart core library.
3488 ObjectStore* object_store = IsolateGroup::Current()->object_store();
3489 const Library& core_lib = Library::Handle(object_store->core_library());
3490 name = String::New("Stopwatch");
3491 const Class& stopwatch_cls = Class::Handle(core_lib.LookupClass(name));
3492
3493 // Keep track of how many subclasses an Stopwatch has.
3494 auto& subclasses =
3496 intptr_t saved_subclass_count = subclasses.IsNull() ? 0 : subclasses.Length();
3497
3498 const char* kScript =
3499 "class AStopwatch extends Stopwatch {\n"
3500 "}\n"
3501 "main() {\n"
3502 " new AStopwatch();\n" // Force finalization.
3503 " return 1;\n"
3504 "}\n";
3505
3506 {
3507 TransitionVMToNative transition(thread);
3508 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3509 EXPECT_VALID(lib);
3510 EXPECT_EQ(1, SimpleInvoke(lib, "main"));
3511 }
3512
3513 // Stopwatch has one new subclass.
3514 subclasses = stopwatch_cls.direct_subclasses_unsafe();
3515 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
3516
3517 // The new subclass is named AStopwatch.
3518 new_subclass = subclasses.At(subclasses.Length() - 1);
3519 name = Class::Cast(new_subclass).Name();
3520 EXPECT_STREQ("AStopwatch", name.ToCString());
3521
3522 const char* kReloadScript =
3523 "class BStopwatch extends Stopwatch {\n"
3524 "}\n"
3525 "main() {\n"
3526 " new BStopwatch();\n" // Force finalization.
3527 " return 2;\n"
3528 "}\n";
3529
3530 {
3531 TransitionVMToNative transition(thread);
3532 Dart_Handle lib = TestCase::ReloadTestScript(kReloadScript);
3533 EXPECT_VALID(lib);
3534 EXPECT_EQ(2, SimpleInvoke(lib, "main"));
3535 }
3536
3537 // Stopwatch has two non-core subclasses.
3538 subclasses = stopwatch_cls.direct_subclasses_unsafe();
3539 EXPECT_EQ(saved_subclass_count + 2, subclasses.Length());
3540
3541 // The non-core subclasses are AStopwatch and BStopwatch.
3542 new_subclass = subclasses.At(subclasses.Length() - 2);
3543 name = Class::Cast(new_subclass).Name();
3544 EXPECT_STREQ("AStopwatch", name.ToCString());
3545
3546 new_subclass = subclasses.At(subclasses.Length() - 1);
3547 name = Class::Cast(new_subclass).Name();
3548 EXPECT_STREQ("BStopwatch", name.ToCString());
3549}
3550
3551// Make sure that we restore the direct subclass info when we revert.
3552ISOLATE_UNIT_TEST_CASE(IsolateReload_DirectSubclasses_Failure) {
3553 Object& new_subclass = Object::Handle();
3555
3556 // Lookup the Stopwatch class by name from the dart core library.
3557 ObjectStore* object_store = IsolateGroup::Current()->object_store();
3558 const Library& core_lib = Library::Handle(object_store->core_library());
3559 name = String::New("Stopwatch");
3560 const Class& stopwatch_cls = Class::Handle(core_lib.LookupClass(name));
3561
3562 // Keep track of how many subclasses an Stopwatch has.
3563 auto& subclasses =
3565 intptr_t saved_subclass_count = subclasses.IsNull() ? 0 : subclasses.Length();
3566
3567 const char* kScript =
3568 "class AStopwatch extends Stopwatch {\n"
3569 "}\n"
3570 "class Foo {\n"
3571 " final a;\n"
3572 " Foo(this.a);\n"
3573 "}\n"
3574 "main() {\n"
3575 " new AStopwatch();\n" // Force finalization.
3576 " new Foo(5);\n" // Force finalization.
3577 " return 1;\n"
3578 "}\n";
3579
3580 {
3581 TransitionVMToNative transition(thread);
3582 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3583 EXPECT_VALID(lib);
3584 EXPECT_EQ(1, SimpleInvoke(lib, "main"));
3585 }
3586
3587 // Stopwatch has one non-core subclass...
3588 subclasses = stopwatch_cls.direct_subclasses_unsafe();
3589 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
3590
3591 // ... and the non-core subclass is named AStopwatch.
3592 subclasses = stopwatch_cls.direct_subclasses_unsafe();
3593 new_subclass = subclasses.At(subclasses.Length() - 1);
3594 name = Class::Cast(new_subclass).Name();
3595 EXPECT_STREQ("AStopwatch", name.ToCString());
3596
3597 // Attempt to reload with a bogus script.
3598 const char* kReloadScript =
3599 "class BStopwatch extends Stopwatch {\n"
3600 "}\n"
3601 "class Foo {\n"
3602 " final a kjsdf ksjdf ;\n" // When we refinalize, we get an error.
3603 " Foo(this.a);\n"
3604 "}\n"
3605 "main() {\n"
3606 " new BStopwatch();\n" // Force finalization.
3607 " new Foo(5);\n" // Force finalization.
3608 " return 2;\n"
3609 "}\n";
3610
3611 {
3612 TransitionVMToNative transition(thread);
3613 Dart_Handle lib = TestCase::ReloadTestScript(kReloadScript);
3614 EXPECT_ERROR(lib, "Expected ';' after this");
3615 }
3616
3617 // If we don't clean up the subclasses, we would find BStopwatch in
3618 // the list of subclasses, which would be bad. Make sure that
3619 // Stopwatch still has only one non-core subclass...
3620 subclasses = stopwatch_cls.direct_subclasses_unsafe();
3621 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
3622
3623 // ...and the non-core subclass is still named AStopwatch.
3624 new_subclass = subclasses.At(subclasses.Length() - 1);
3625 name = Class::Cast(new_subclass).Name();
3626 EXPECT_STREQ("AStopwatch", name.ToCString());
3627}
3628
3629// Tests reload succeeds when instance format changes.
3630// Change: Foo {a, b, c:42} -> Foo {c:42}
3631// Validate: c keeps the value in the retained Foo object.
3632TEST_CASE(IsolateReload_ChangeInstanceFormat0) {
3633 const char* kScript =
3634 "class Foo {\n"
3635 " var a;\n"
3636 " var b;\n"
3637 " var c;\n"
3638 "}\n"
3639 "var f;\n"
3640 "main() {\n"
3641 " f = new Foo();\n"
3642 " f.c = 42;\n"
3643 " return f.c;\n"
3644 "}\n";
3645
3646 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3647 EXPECT_VALID(lib);
3648 EXPECT_EQ(42, SimpleInvoke(lib, "main"));
3649
3650 const char* kReloadScript =
3651 "class Foo {\n"
3652 " var c;\n"
3653 "}\n"
3654 "var f;\n"
3655 "main() {\n"
3656 " return f.c;\n"
3657 "}\n";
3658
3659 lib = TestCase::ReloadTestScript(kReloadScript);
3660 EXPECT_VALID(lib);
3661 EXPECT_EQ(42, SimpleInvoke(lib, "main"));
3662}
3663
3664// Tests reload succeeds when instance format changes.
3665// Change: Foo {} -> Foo {c:null}
3666// Validate: c is initialized to null the retained Foo object.
3667TEST_CASE(IsolateReload_ChangeInstanceFormat1) {
3668 const char* kScript =
3669 "class Foo {\n"
3670 "}\n"
3671 "var f;\n"
3672 "main() {\n"
3673 " f = new Foo();\n"
3674 " return 42;\n"
3675 "}\n";
3676
3677 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3678 EXPECT_VALID(lib);
3679 EXPECT_EQ(42, SimpleInvoke(lib, "main"));
3680
3681 const char* kReloadScript =
3682 "class Foo {\n"
3683 " var c;\n"
3684 "}\n"
3685 "var f;\n"
3686 "main() {\n"
3687 " return (f.c == null) ? 42: 21;\n"
3688 "}\n";
3689
3690 lib = TestCase::ReloadTestScript(kReloadScript);
3691 EXPECT_VALID(lib);
3692 EXPECT_EQ(42, SimpleInvoke(lib, "main"));
3693}
3694
3695// Tests reload succeeds when instance format changes.
3696// Change: Foo {c:42} -> Foo {}
3697// Validate: running the after script fails.
3698TEST_CASE(IsolateReload_ChangeInstanceFormat2) {
3699 const char* kScript =
3700 "class Foo {\n"
3701 " var c;\n"
3702 "}\n"
3703 "var f;\n"
3704 "main() {\n"
3705 " f = new Foo();\n"
3706 " f.c = 42;\n"
3707 " return f.c;\n"
3708 "}\n";
3709
3710 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3711 EXPECT_VALID(lib);
3712 EXPECT_EQ(42, SimpleInvoke(lib, "main"));
3713
3714 const char* kReloadScript =
3715 "class Foo {\n"
3716 "}\n"
3717 "var f;\n"
3718 "main() {\n"
3719 " try {\n"
3720 " return f.c;\n"
3721 " } catch (e) {\n"
3722 " return 24;\n"
3723 " }\n"
3724 "}\n";
3725
3726 lib = TestCase::ReloadTestScript(kReloadScript);
3727 EXPECT_VALID(lib);
3728 EXPECT_EQ(24, SimpleInvoke(lib, "main"));
3729}
3730
3731// Tests reload succeeds when instance format changes.
3732// Change: Foo {a, b, c:42, d} -> Foo {c:42, g}
3733// Validate: c keeps the value in the retained Foo object.
3734TEST_CASE(IsolateReload_ChangeInstanceFormat3) {
3735 const char* kScript =
3736 "class Foo<A,B> {\n"
3737 " var a;\n"
3738 " var b;\n"
3739 " var c;\n"
3740 " var d;\n"
3741 "}\n"
3742 "var f;\n"
3743 "main() {\n"
3744 " f = new Foo();\n"
3745 " f.a = 1;\n"
3746 " f.b = 2;\n"
3747 " f.c = 3;\n"
3748 " f.d = 4;\n"
3749 " return f.c;\n"
3750 "}\n";
3751
3752 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3753 EXPECT_VALID(lib);
3754 EXPECT_EQ(3, SimpleInvoke(lib, "main"));
3755
3756 const char* kReloadScript =
3757 "class Foo<A,B> {\n"
3758 " var c;\n"
3759 " var g;\n"
3760 "}\n"
3761 "var f;\n"
3762 "main() {\n"
3763 " return f.c;\n"
3764 "}\n";
3765
3766 lib = TestCase::ReloadTestScript(kReloadScript);
3767 EXPECT_VALID(lib);
3768 EXPECT_EQ(3, SimpleInvoke(lib, "main"));
3769}
3770
3771// Tests reload succeeds when instance format changes.
3772// Change: Bar {c:42}, Foo : Bar {d, e} -> Foo {c:42}
3773// Validate: c keeps the value in the retained Foo object.
3774TEST_CASE(IsolateReload_ChangeInstanceFormat4) {
3775 const char* kScript =
3776 "class Bar{\n"
3777 " var c;\n"
3778 "}\n"
3779 "class Foo extends Bar{\n"
3780 " var d;\n"
3781 " var e;\n"
3782 "}\n"
3783 "var f;\n"
3784 "main() {\n"
3785 " f = new Foo();\n"
3786 " f.c = 44;\n"
3787 " return f.c;\n"
3788 "}\n";
3789
3790 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3791 EXPECT_VALID(lib);
3792 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
3793
3794 const char* kReloadScript =
3795 "class Foo {\n"
3796 " var c;\n"
3797 "}\n"
3798 "var f;\n"
3799 "main() {\n"
3800 " return f.c;\n"
3801 "}\n";
3802
3803 lib = TestCase::ReloadTestScript(kReloadScript);
3804 EXPECT_VALID(lib);
3805 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
3806}
3807
3808// Tests reload succeeds when instance format changes.
3809// Change: Bar {a, b}, Foo : Bar {c:42} -> Bar {c:42}, Foo : Bar {}
3810// Validate: c keeps the value in the retained Foo object.
3811TEST_CASE(IsolateReload_ChangeInstanceFormat5) {
3812 const char* kScript =
3813 "class Bar{\n"
3814 " var a;\n"
3815 " var b;\n"
3816 "}\n"
3817 "class Foo extends Bar{\n"
3818 " var c;\n"
3819 "}\n"
3820 "var f;\n"
3821 "main() {\n"
3822 " f = new Foo();\n"
3823 " f.c = 44;\n"
3824 " return f.c;\n"
3825 "}\n";
3826
3827 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3828 EXPECT_VALID(lib);
3829 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
3830
3831 const char* kReloadScript =
3832 "class Bar{\n"
3833 " var c;\n"
3834 "}\n"
3835 "class Foo extends Bar {\n"
3836 "}\n"
3837 "var f;\n"
3838 "main() {\n"
3839 " return f.c;\n"
3840 "}\n";
3841
3842 lib = TestCase::ReloadTestScript(kReloadScript);
3843 EXPECT_VALID(lib);
3844 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
3845}
3846
3847// Tests reload fails when type parameters change.
3848// Change: Foo<A,B> {a, b} -> Foo<A> {a}
3849// Validate: the right error message is returned.
3850TEST_CASE(IsolateReload_ChangeInstanceFormat6) {
3851 const char* kScript =
3852 "class Foo<A, B> {\n"
3853 " var a;\n"
3854 " var b;\n"
3855 "}\n"
3856 "main() {\n"
3857 " new Foo();\n"
3858 " return 43;\n"
3859 "}\n";
3860
3861 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3862 EXPECT_VALID(lib);
3863 EXPECT_EQ(43, SimpleInvoke(lib, "main"));
3864
3865 const char* kReloadScript =
3866 "class Foo<A> {\n"
3867 " var a;\n"
3868 "}\n";
3869 lib = TestCase::ReloadTestScript(kReloadScript);
3870 EXPECT_ERROR(lib, "type parameters have changed");
3871}
3872
3873// Tests reload succeeds when type parameters are changed for allocated class.
3874// Change: Foo<A,B> {a, b} -> Foo<A> {a}
3875// Validate: return value from main is correct.
3876// Please note: This test works because no instances are created from Foo.
3877TEST_CASE(IsolateReload_ChangeInstanceFormat7) {
3878 const char* kScript =
3879 "class Foo<A, B> {\n"
3880 " var a;\n"
3881 " var b;\n"
3882 "}\n";
3883
3884 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3885 EXPECT_VALID(lib);
3886
3887 const char* kReloadScript =
3888 "class Foo<A> {\n"
3889 " var a;\n"
3890 "}\n";
3891 lib = TestCase::ReloadTestScript(kReloadScript);
3892 EXPECT_VALID(lib);
3893}
3894
3895// Regression for handle sharing bug: Change the shape of two classes and see
3896// that their instances don't change class.
3897TEST_CASE(IsolateReload_ChangeInstanceFormat8) {
3898 const char* kScript =
3899 "class A{\n"
3900 " var x;\n"
3901 "}\n"
3902 "class B {\n"
3903 " var x, y, z, w;\n"
3904 "}\n"
3905 "var a, b;\n"
3906 "main() {\n"
3907 " a = new A();\n"
3908 " b = new B();\n"
3909 " return '$a $b';\n"
3910 "}\n";
3911
3912 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3913 EXPECT_VALID(lib);
3914 EXPECT_STREQ("Instance of 'A' Instance of 'B'", SimpleInvokeStr(lib, "main"));
3915
3916 const char* kReloadScript =
3917 "class A{\n"
3918 " var x, y;\n"
3919 "}\n"
3920 "class B {\n"
3921 " var x, y, z, w, v;\n"
3922 "}\n"
3923 "var a, b;\n"
3924 "main() {\n"
3925 " return '$a $b';\n"
3926 "}\n";
3927
3928 lib = TestCase::ReloadTestScript(kReloadScript);
3929 EXPECT_VALID(lib);
3930 EXPECT_STREQ("Instance of 'A' Instance of 'B'", SimpleInvokeStr(lib, "main"));
3931}
3932
3933// Tests reload fails when type arguments change.
3934// Change: Baz extends Foo<String> -> Baz extends Bar<String, double>
3935// Validate: the right error message is returned.
3936TEST_CASE(IsolateReload_ChangeInstanceFormat9) {
3937 const char* kScript =
3938 "class Foo<A> {\n"
3939 " var a;\n"
3940 "}\n"
3941 "class Bar<B, C> extends Foo<B> {}\n"
3942 "class Baz extends Foo<String> {}"
3943 "main() {\n"
3944 " new Baz();\n"
3945 " return 43;\n"
3946 "}\n";
3947
3948 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3949 EXPECT_VALID(lib);
3950 EXPECT_EQ(43, SimpleInvoke(lib, "main"));
3951
3952 const char* kReloadScript =
3953 "class Foo<A> {\n"
3954 " var a;\n"
3955 "}\n"
3956 "class Bar<B, C> extends Foo<B> {}\n"
3957 "class Baz extends Bar<String, double> {}"
3958 "main() {\n"
3959 " new Baz();\n"
3960 " return 43;\n"
3961 "}\n";
3962 lib = TestCase::ReloadTestScript(kReloadScript);
3963 EXPECT_ERROR(lib, "type parameters have changed");
3964}
3965
3966TEST_CASE(IsolateReload_ShapeChangeMutualReference) {
3967 const char* kScript =
3968 "class A{\n"
3969 " var x;\n"
3970 " get yourself => this;\n"
3971 "}\n"
3972 "var retained1;\n"
3973 "var retained2;\n"
3974 "main() {\n"
3975 " retained1 = new A();\n"
3976 " retained2 = new A();\n"
3977 " retained1.x = retained2;\n"
3978 " retained2.x = retained1;\n"
3979 " return '${identical(retained1.x.yourself, retained2)}'\n"
3980 " '${identical(retained2.x.yourself, retained1)}';\n"
3981 "}\n";
3982
3983 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
3984 EXPECT_VALID(lib);
3985 EXPECT_STREQ("truetrue", SimpleInvokeStr(lib, "main"));
3986
3987 const char* kReloadScript =
3988 "class A{\n"
3989 " var x;\n"
3990 " var y;\n"
3991 " var z;\n"
3992 " var w;\n"
3993 " get yourself => this;\n"
3994 "}\n"
3995 "var retained1;\n"
3996 "var retained2;\n"
3997 "main() {\n"
3998 " return '${identical(retained1.x.yourself, retained2)}'\n"
3999 " '${identical(retained2.x.yourself, retained1)}';\n"
4000 "}\n";
4001
4002 lib = TestCase::ReloadTestScript(kReloadScript);
4003 EXPECT_VALID(lib);
4004 EXPECT_STREQ("truetrue", SimpleInvokeStr(lib, "main"));
4005}
4006
4007TEST_CASE(IsolateReload_ShapeChangeRetainsHash) {
4008 const char* kScript =
4009 "class A{\n"
4010 " var x;\n"
4011 "}\n"
4012 "var a, hash1, hash2;\n"
4013 "main() {\n"
4014 " a = new A();\n"
4015 " hash1 = a.hashCode;\n"
4016 " return 'okay';\n"
4017 "}\n";
4018
4019 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4020 EXPECT_VALID(lib);
4021 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
4022
4023 const char* kReloadScript =
4024 "class A{\n"
4025 " var x, y, z;\n"
4026 "}\n"
4027 "var a, hash1, hash2;\n"
4028 "main() {\n"
4029 " hash2 = a.hashCode;\n"
4030 " return (hash1 == hash2).toString();\n"
4031 "}\n";
4032
4033 lib = TestCase::ReloadTestScript(kReloadScript);
4034 EXPECT_VALID(lib);
4035 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
4036}
4037
4038TEST_CASE(IsolateReload_ShapeChangeRetainsHash_Const) {
4039 const char* kScript =
4040 "class A {\n"
4041 " final x;\n"
4042 " const A(this.x);\n"
4043 "}\n"
4044 "var a, hash1, hash2;\n"
4045 "main() {\n"
4046 " a = const A(1);\n"
4047 " hash1 = a.hashCode;\n"
4048 " return 'okay';\n"
4049 "}\n";
4050
4051 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4052 EXPECT_VALID(lib);
4053 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
4054
4055 const char* kReloadScript =
4056 "class A {\n"
4057 " final x, y, z;\n"
4058 " const A(this.x, this.y, this.z);\n"
4059 "}\n"
4060 "var a, hash1, hash2;\n"
4061 "main() {\n"
4062 " hash2 = a.hashCode;\n"
4063 " return (hash1 == hash2).toString();\n"
4064 "}\n";
4065
4066 lib = TestCase::ReloadTestScript(kReloadScript);
4067 EXPECT_VALID(lib);
4068 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
4069}
4070
4071TEST_CASE(IsolateReload_ShapeChange_Const_AddSlot) {
4072 // On IA32, instructions can contain direct pointers to const objects. We need
4073 // to be careful that if the const objects are reallocated because of a shape
4074 // change, they are allocated old. Because instructions normally contain
4075 // pointers only to old objects, the scavenger does not bother to ensure code
4076 // pages are writable when visiting the remembered set. Visiting the
4077 // remembered involves writing to update the pointer for any target that gets
4078 // promoted.
4079 const char* kScript = R"(
4080 import 'file:///test:isolate_reload_helper';
4081 class A {
4082 final x;
4083 const A(this.x);
4084 }
4085 var a;
4086 main() {
4087 a = const A(1);
4088 collectNewSpace();
4089 return 'okay';
4090 }
4091 )";
4092
4093 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4094 EXPECT_VALID(lib);
4095 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
4096
4097 const char* kReloadScript = R"(
4098 import 'file:///test:isolate_reload_helper';
4099 class A {
4100 final x, y, z;
4101 const A(this.x, this.y, this.z);
4102 }
4103 var a;
4104 main() {
4105 a = const A(1, null, null);
4106 collectNewSpace();
4107 return 'okay';
4108 }
4109 )";
4110
4111 lib = TestCase::ReloadTestScript(kReloadScript);
4112 EXPECT_VALID(lib);
4113 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
4114
4115 const char* kReloadScript2 = R"(
4116 import 'file:///test:isolate_reload_helper';
4117 class A {
4118 final x, y, z, w, u;
4119 const A(this.x, this.y, this.z, this.w, this.u);
4120 }
4121 var a;
4122 main() {
4123 a = const A(1, null, null, null, null);
4124 collectNewSpace();
4125 return 'okay';
4126 }
4127 )";
4128
4129 lib = TestCase::ReloadTestScript(kReloadScript2);
4130 EXPECT_VALID(lib);
4131 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
4132}
4133
4134TEST_CASE(IsolateReload_ShapeChange_Const_RemoveSlot) {
4135 const char* kScript = R"(
4136 import 'file:///test:isolate_reload_helper';
4137 class A {
4138 final x, y, z;
4139 const A(this.x, this.y, this.z);
4140 }
4141 var a;
4142 main() {
4143 a = const A(1, 2, 3);
4144 collectNewSpace();
4145 return 'okay';
4146 }
4147 )";
4148
4149 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4150 EXPECT_VALID(lib);
4151 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
4152
4153 const char* kReloadScript = R"(
4154 import 'file:///test:isolate_reload_helper';
4155 class A {
4156 final x, y;
4157 const A(this.x, this.y);
4158 }
4159 var a;
4160 main() {
4161 a = const A(1, null);
4162 collectNewSpace();
4163 return 'okay';
4164 }
4165 )";
4166
4167 lib = TestCase::ReloadTestScript(kReloadScript);
4168 EXPECT_ERROR(lib,
4169 "Const class cannot remove fields: "
4170 "Library:'file:///test-lib' Class: A");
4171
4172 // Rename is seen by the VM is unrelated add and remove.
4173 const char* kReloadScript2 = R"(
4174 import 'file:///test:isolate_reload_helper';
4175 class A {
4176 final x, y, w;
4177 const A(this.x, this.y, this.w);
4178 }
4179 var a;
4180 main() {
4181 a = const A(1, null, null);
4182 collectNewSpace();
4183 return 'okay';
4184 }
4185 )";
4186
4187 lib = TestCase::ReloadTestScript(kReloadScript2);
4188 EXPECT_ERROR(lib,
4189 "Const class cannot remove fields: "
4190 "Library:'file:///test-lib' Class: A");
4191}
4192
4193TEST_CASE(IsolateReload_DeeplyImmutableChange) {
4194 const char* kScript = R"(
4195 @pragma('vm:deeply-immutable')
4196 final class A {
4197 final int x;
4198 A(this.x);
4199 }
4200 String main () {
4201 A(123);
4202 return 'okay';
4203 }
4204 )";
4205
4206 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4207 EXPECT_VALID(lib);
4208 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
4209
4210 const char* kReloadScript = R"(
4211 final class A {
4212 final int x;
4213 A(this.x);
4214 }
4215 String main () {
4216 A(123);
4217 return 'okay';
4218 }
4219 )";
4220
4221 lib = TestCase::ReloadTestScript(kReloadScript);
4222 EXPECT_ERROR(lib,
4223 "Classes cannot change their @pragma('vm:deeply-immutable'): "
4224 "Library:'file:///test-lib' Class: A");
4225}
4226
4227TEST_CASE(IsolateReload_DeeplyImmutableChange_2) {
4228 const char* kScript = R"(
4229 final class A {
4230 final int x;
4231 A(this.x);
4232 }
4233 String main () {
4234 A(123);
4235 return 'okay';
4236 }
4237 )";
4238
4239 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4240 EXPECT_VALID(lib);
4241 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
4242
4243 const char* kReloadScript = R"(
4244 @pragma('vm:deeply-immutable')
4245 final class A {
4246 final int x;
4247 A(this.x);
4248 }
4249 String main () {
4250 A(123);
4251 return 'okay';
4252 }
4253 )";
4254
4255 lib = TestCase::ReloadTestScript(kReloadScript);
4256 EXPECT_ERROR(lib,
4257 "Classes cannot change their @pragma('vm:deeply-immutable'): "
4258 "Library:'file:///test-lib' Class: A");
4259}
4260
4261TEST_CASE(IsolateReload_DeeplyImmutableChange_MultiLib) {
4262 // clang-format off
4263 Dart_SourceFile sourcefiles[] = {
4264 {
4265 "file:///test-app.dart",
4266 R"(
4267 import 'test-lib.dart';
4268
4269 @pragma('vm:deeply-immutable')
4270 final class A {
4271 final B b;
4272 A(this.b);
4273 }
4274 int main () {
4275 A(B(123));
4276 return 42;
4277 }
4278 )",
4279 },
4280 {
4281 "file:///test-lib.dart",
4282 R"(
4283 @pragma('vm:deeply-immutable')
4284 final class B {
4285 final int x;
4286 B(this.x);
4287 }
4288 )"
4289 }};
4290 // clang-format on
4291
4293 sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
4294 nullptr /* resolver */, true /* finalize */, true /* incrementally */);
4295 EXPECT_VALID(lib);
4296 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
4297 int64_t value = 0;
4300 EXPECT_EQ(42, value);
4301
4302 // clang-format off
4303 Dart_SourceFile updated_sourcefiles[] = {
4304 {
4305 "file:///test-lib.dart",
4306 R"(
4307 final class B {
4308 final int x;
4309 B(this.x);
4310 }
4311 )"
4312 }};
4313 // clang-format on
4314
4315 {
4316 const uint8_t* kernel_buffer = nullptr;
4317 intptr_t kernel_buffer_size = 0;
4319 "file:///test-app.dart",
4320 sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
4321 updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
4322 true /* incrementally */);
4323 // This is rejected by class A being recompiled and the validator failing.
4324 EXPECT(error != nullptr);
4325 EXPECT_NULLPTR(kernel_buffer);
4326 }
4327}
4328
4329TEST_CASE(IsolateReload_DeeplyImmutableChange_TypeBound) {
4330 // clang-format off
4331 Dart_SourceFile sourcefiles[] = {
4332 {
4333 "file:///test-app.dart",
4334 R"(
4335 import 'test-lib.dart';
4336
4337 @pragma('vm:deeply-immutable')
4338 final class A<T extends B> {
4339 final T b;
4340 A(this.b);
4341 }
4342 int main () {
4343 A(B(123));
4344 return 42;
4345 }
4346 )",
4347 },
4348 {
4349 "file:///test-lib.dart",
4350 R"(
4351 @pragma('vm:deeply-immutable')
4352 final class B {
4353 final int x;
4354 B(this.x);
4355 }
4356 )"
4357 }};
4358 // clang-format on
4359
4361 sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
4362 nullptr /* resolver */, true /* finalize */, true /* incrementally */);
4363 EXPECT_VALID(lib);
4364 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
4365 int64_t value = 0;
4368 EXPECT_EQ(42, value);
4369
4370 // clang-format off
4371 Dart_SourceFile updated_sourcefiles[] = {
4372 {
4373 "file:///test-lib.dart",
4374 R"(
4375 final class B {
4376 final int x;
4377 B(this.x);
4378 }
4379 )"
4380 }};
4381 // clang-format on
4382
4383 {
4384 const uint8_t* kernel_buffer = nullptr;
4385 intptr_t kernel_buffer_size = 0;
4387 "file:///test-app.dart",
4388 sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
4389 updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
4390 true /* incrementally */);
4391 // This is rejected by class A being recompiled and the validator failing.
4392 EXPECT(error != nullptr);
4393 EXPECT_NULLPTR(kernel_buffer);
4394 }
4395}
4396
4397TEST_CASE(IsolateReload_ConstToNonConstClass) {
4398 const char* kScript = R"(
4399 class A {
4400 final dynamic x;
4401 const A(this.x);
4402 }
4403 dynamic a;
4404 main() {
4405 a = const A(1);
4406 return 'okay';
4407 }
4408 )";
4409
4410 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4411 EXPECT_VALID(lib);
4412 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
4413
4414 const char* kReloadScript = R"(
4415 class A {
4416 dynamic x;
4417 A(this.x);
4419 dynamic a;
4420 main() {
4421 a.x = 10;
4422 }
4423 )";
4424
4425 lib = TestCase::ReloadTestScript(kReloadScript);
4426 EXPECT_ERROR(lib,
4427 "Const class cannot become non-const: "
4428 "Library:'file:///test-lib' Class: A");
4429}
4430
4431TEST_CASE(IsolateReload_ConstToNonConstClass_Empty) {
4432 const char* kScript = R"(
4433 class A {
4434 const A();
4435 }
4436 dynamic a;
4437 main() {
4438 a = const A();
4439 return 'okay';
4440 }
4441 )";
4442
4443 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4445 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
4446
4447 const char* kReloadScript = R"(
4448 class A {
4449 dynamic x;
4450 A(this.x);
4451 }
4452 dynamic a;
4453 main() {
4454 a.x = 10;
4455 }
4456 )";
4457
4458 lib = TestCase::ReloadTestScript(kReloadScript);
4459 EXPECT_ERROR(lib,
4460 "Const class cannot become non-const: "
4461 "Library:'file:///test-lib' Class: A");
4462}
4463
4464TEST_CASE(IsolateReload_StaticTearOffRetainsHash) {
4465 const char* kScript =
4466 "foo() {}\n"
4467 "var hash1, hash2;\n"
4468 "main() {\n"
4469 " hash1 = foo.hashCode;\n"
4470 " return 'okay';\n"
4471 "}\n";
4472
4473 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4474 EXPECT_VALID(lib);
4475 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
4476
4477 const char* kReloadScript =
4478 "foo() {}\n"
4479 "var hash1, hash2;\n"
4480 "main() {\n"
4481 " hash2 = foo.hashCode;\n"
4482 " return (hash1 == hash2).toString();\n"
4483 "}\n";
4484
4485 lib = TestCase::ReloadTestScript(kReloadScript);
4486 EXPECT_VALID(lib);
4487 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
4489
4490static bool NothingModifiedCallback(const char* url, int64_t since) {
4491 return false;
4492}
4493
4494TEST_CASE(IsolateReload_NoLibsModified) {
4495 const char* kImportScript = "importedFunc() => 'fancy';";
4496 TestCase::AddTestLib("test:lib1", kImportScript);
4497
4498 const char* kScript =
4499 "import 'test:lib1';\n"
4500 "main() {\n"
4501 " return importedFunc() + ' feast';\n"
4502 "}\n";
4503
4504 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4505 EXPECT_VALID(lib);
4506 EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
4507
4508 const char* kReloadImportScript = "importedFunc() => 'bossy';";
4509 TestCase::AddTestLib("test:lib1", kReloadImportScript);
4510
4511 const char* kReloadScript =
4512 "import 'test:lib1';\n"
4513 "main() {\n"
4514 " return importedFunc() + ' pants';\n"
4515 "}\n";
4516
4518 lib = TestCase::ReloadTestScript(kReloadScript);
4519 EXPECT_VALID(lib);
4521
4522 // No reload occurred because no files were "modified".
4523 EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
4524}
4525
4526static bool MainModifiedCallback(const char* url, int64_t since) {
4527 if ((strcmp(url, "test-lib") == 0) ||
4528 (strcmp(url, "file:///test-lib") == 0)) {
4529 return true;
4530 }
4531 return false;
4532}
4533
4534TEST_CASE(IsolateReload_MainLibModified) {
4535 const char* kImportScript = "importedFunc() => 'fancy';";
4536 TestCase::AddTestLib("test:lib1", kImportScript);
4537
4538 const char* kScript =
4539 "import 'test:lib1';\n"
4540 "main() {\n"
4541 " return importedFunc() + ' feast';\n"
4542 "}\n";
4543
4544 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4545 EXPECT_VALID(lib);
4546 EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
4547
4548 const char* kReloadImportScript = "importedFunc() => 'bossy';";
4549 TestCase::AddTestLib("test:lib1", kReloadImportScript);
4550
4551 const char* kReloadScript =
4552 "import 'test:lib1';\n"
4553 "main() {\n"
4554 " return importedFunc() + ' pants';\n"
4555 "}\n";
4556
4558 lib = TestCase::ReloadTestScript(kReloadScript);
4561
4562 // Imported library is not reloaded.
4563 EXPECT_STREQ("fancy pants", SimpleInvokeStr(lib, "main"));
4564}
4565
4566static bool ImportModifiedCallback(const char* url, int64_t since) {
4567 if (strcmp(url, "test:lib1") == 0) {
4568 return true;
4569 }
4570 return false;
4571}
4572
4573TEST_CASE(IsolateReload_ImportedLibModified) {
4574 const char* kImportScript = "importedFunc() => 'fancy';";
4575 TestCase::AddTestLib("test:lib1", kImportScript);
4576
4577 const char* kScript =
4578 "import 'test:lib1';\n"
4579 "main() {\n"
4580 " return importedFunc() + ' feast';\n"
4581 "}\n";
4582
4583 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4584 EXPECT_VALID(lib);
4585 EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
4586
4587 const char* kReloadImportScript = "importedFunc() => 'bossy';";
4588 TestCase::AddTestLib("test:lib1", kReloadImportScript);
4589
4590 const char* kReloadScript =
4591 "import 'test:lib1';\n"
4592 "main() {\n"
4593 " return importedFunc() + ' pants';\n"
4594 "}\n";
4595
4597 lib = TestCase::ReloadTestScript(kReloadScript);
4598 EXPECT_VALID(lib);
4600
4601 // Modification of an imported library propagates to the importing library.
4602 EXPECT_STREQ("bossy pants", SimpleInvokeStr(lib, "main"));
4603}
4604
4605TEST_CASE(IsolateReload_PrefixImportedLibModified) {
4606 const char* kImportScript = "importedFunc() => 'fancy';";
4607 TestCase::AddTestLib("test:lib1", kImportScript);
4608
4609 const char* kScript =
4610 "import 'test:lib1' as cobra;\n"
4611 "main() {\n"
4612 " return cobra.importedFunc() + ' feast';\n"
4613 "}\n";
4614
4615 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4616 EXPECT_VALID(lib);
4617 EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
4618
4619 const char* kReloadImportScript = "importedFunc() => 'bossy';";
4620 TestCase::AddTestLib("test:lib1", kReloadImportScript);
4621
4622 const char* kReloadScript =
4623 "import 'test:lib1' as cobra;\n"
4624 "main() {\n"
4625 " return cobra.importedFunc() + ' pants';\n"
4626 "}\n";
4627
4629 lib = TestCase::ReloadTestScript(kReloadScript);
4630 EXPECT_VALID(lib);
4632
4633 // Modification of an prefix-imported library propagates to the
4634 // importing library.
4635 EXPECT_STREQ("bossy pants", SimpleInvokeStr(lib, "main"));
4636}
4637
4638static bool ExportModifiedCallback(const char* url, int64_t since) {
4639 if (strcmp(url, "test:exportlib") == 0) {
4640 return true;
4641 }
4642 return false;
4643}
4644
4645TEST_CASE(IsolateReload_ExportedLibModified) {
4646 const char* kImportScript = "export 'test:exportlib';";
4647 TestCase::AddTestLib("test:importlib", kImportScript);
4648
4649 const char* kExportScript = "exportedFunc() => 'fancy';";
4650 TestCase::AddTestLib("test:exportlib", kExportScript);
4651
4652 const char* kScript =
4653 "import 'test:importlib';\n"
4654 "main() {\n"
4655 " return exportedFunc() + ' feast';\n"
4656 "}\n";
4657
4658 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4659 EXPECT_VALID(lib);
4660 EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
4661
4662 const char* kReloadExportScript = "exportedFunc() => 'bossy';";
4663 TestCase::AddTestLib("test:exportlib", kReloadExportScript);
4664
4665 const char* kReloadScript =
4666 "import 'test:importlib';\n"
4667 "main() {\n"
4668 " return exportedFunc() + ' pants';\n"
4669 "}\n";
4670
4672 lib = TestCase::ReloadTestScript(kReloadScript);
4673 EXPECT_VALID(lib);
4675
4676 // Modification of an exported library propagates.
4677 EXPECT_STREQ("bossy pants", SimpleInvokeStr(lib, "main"));
4679
4680TEST_CASE(IsolateReload_SimpleConstFieldUpdate) {
4681 const char* kScript =
4682 "const value = 'a';\n"
4683 "main() {\n"
4684 " return 'value=${value}';\n"
4685 "}\n";
4686
4687 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4688 EXPECT_VALID(lib);
4689 EXPECT_STREQ("value=a", SimpleInvokeStr(lib, "main"));
4690
4691 const char* kReloadScript =
4692 "const value = 'b';\n"
4693 "main() {\n"
4694 " return 'value=${value}';\n"
4695 "}\n";
4696
4697 lib = TestCase::ReloadTestScript(kReloadScript);
4698 EXPECT_VALID(lib);
4699 EXPECT_STREQ("value=b", SimpleInvokeStr(lib, "main"));
4700}
4701
4702TEST_CASE(IsolateReload_ConstFieldUpdate) {
4703 const char* kScript =
4704 "const value = const Duration(seconds: 1);\n"
4705 "main() {\n"
4706 " return 'value=${value}';\n"
4707 "}\n";
4708
4709 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
4710 EXPECT_VALID(lib);
4711 EXPECT_STREQ("value=0:00:01.000000", SimpleInvokeStr(lib, "main"));
4712
4713 const char* kReloadScript =
4714 "const value = const Duration(seconds: 2);\n"
4715 "main() {\n"
4716 " return 'value=${value}';\n"
4717 "}\n";
4718
4719 lib = TestCase::ReloadTestScript(kReloadScript);
4720 EXPECT_VALID(lib);
4721 EXPECT_STREQ("value=0:00:02.000000", SimpleInvokeStr(lib, "main"));
4722}
4723
4724TEST_CASE(IsolateReload_RunNewFieldInitializers) {
4725 const char* late_tag = TestCase::LateTag();
4726 // clang-format off
4727 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
4728 "class Foo {\n"
4729 " int x = 4;\n"
4730 "}\n"
4731 "%s Foo value;\n"
4732 "main() {\n"
4733 " value = Foo();\n"
4734 " return value.x;\n"
4735 "}\n",
4736 late_tag),
4737 std::free);
4738 // clang-format on
4739
4740 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
4741 EXPECT_VALID(lib);
4742 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
4743
4744 // Add the field y.
4745 // clang-format off
4746 auto kReloadScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
4747 "class Foo {\n"
4748 " int x = 4;\n"
4749 " int y = 7;\n"
4750 "}\n"
4751 "%s Foo value;\n"
4752 "main() {\n"
4753 " return value.y;\n"
4754 "}\n",
4755 late_tag),
4756 std::free);
4757 // clang-format on
4758
4759 lib = TestCase::ReloadTestScript(kReloadScript.get());
4760 EXPECT_VALID(lib);
4761 // Verify that we ran field initializers on existing instances.
4762 EXPECT_EQ(7, SimpleInvoke(lib, "main"));
4763}
4765TEST_CASE(IsolateReload_RunNewFieldInitializersReferenceStaticField) {
4766 const char* late_tag = TestCase::LateTag();
4767 // clang-format off
4768 auto kScript =
4770 "int myInitialValue = 8 * 7;\n"
4771 "class Foo {\n"
4772 " int x = 4;\n"
4773 "}\n"
4774 "%s Foo value;\n"
4775 "main() {\n"
4776 " value = Foo();\n"
4777 " return value.x;\n"
4778 "}\n",
4779 late_tag),
4780 std::free);
4781 // clang-format on
4782
4783 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
4784 EXPECT_VALID(lib);
4785 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
4786
4787 // Add the field y.
4788 // clang-format off
4789 auto kReloadScript =
4791 "int myInitialValue = 8 * 7;\n"
4792 "class Foo {\n"
4793 " int x = 4;\n"
4794 " int y = myInitialValue;\n"
4795 "}\n"
4796 "%s Foo value;\n"
4797 "main() {\n"
4798 " return value.y;\n"
4799 "}\n",
4800 late_tag),
4801 std::free);
4802 // clang-format on
4803
4804 lib = TestCase::ReloadTestScript(kReloadScript.get());
4805 EXPECT_VALID(lib);
4806 // Verify that we ran field initializers on existing instances.
4807 EXPECT_EQ(56, SimpleInvoke(lib, "main"));
4808}
4809
4810TEST_CASE(IsolateReload_RunNewFieldInitializersLazy) {
4811 const char* late_tag = TestCase::LateTag();
4812 // clang-format off
4813 auto kScript =
4815 "int myInitialValue = 8 * 7;\n"
4816 "class Foo {\n"
4817 " int x = 4;\n"
4818 "}\n"
4819 "%s Foo value;\n"
4820 "%s Foo value1;\n"
4821 "main() {\n"
4822 " value = Foo();\n"
4823 " value1 = Foo();\n"
4824 " return value.x;\n"
4825 "}\n",
4826 late_tag, late_tag),
4827 std::free);
4828 // clang-format on
4829
4830 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
4831 EXPECT_VALID(lib);
4832 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
4833
4834 // Add the field y.
4835 // clang-format off
4836 auto kReloadScript = Utils::CStringUniquePtr(
4837 OS::SCreate(nullptr,
4838 "int myInitialValue = 8 * 7;\n"
4839 "class Foo {\n"
4840 " int x = 4;\n"
4841 " int y = myInitialValue++;\n"
4842 "}\n"
4843 "%s Foo value;\n"
4844 "%s Foo value1;\n"
4845 "main() {\n"
4846 " return '${myInitialValue} ${value.y} ${value1.y} "
4847 "${myInitialValue}';\n"
4848 "}\n",
4849 late_tag, late_tag),
4850 std::free);
4851 // clang-format on
4852
4853 lib = TestCase::ReloadTestScript(kReloadScript.get());
4854 EXPECT_VALID(lib);
4855 // Verify that field initializers ran lazily.
4856 EXPECT_STREQ("56 56 57 58", SimpleInvokeStr(lib, "main"));
4857}
4858
4859TEST_CASE(IsolateReload_RunNewFieldInitializersLazyConst) {
4860 const char* late_tag = TestCase::LateTag();
4861 // clang-format off
4862 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
4863 "class Foo {\n"
4864 " int x = 4;\n"
4865 "}\n"
4866 "%s Foo value;\n"
4867 "main() {\n"
4868 " value = Foo();\n"
4869 " return value.x;\n"
4870 "}\n",
4871 late_tag),
4872 std::free);
4873 // clang-format on
4875 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
4876 EXPECT_VALID(lib);
4877 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
4878
4879 // Add the field y. Do not read it. Note field y does not get an initializer
4880 // function in the VM because the initializer is a literal, but we should not
4881 // eagerly initialize with the literal so that the behavior doesn't depend on
4882 // this optimization.
4883 // clang-format off
4884 auto kReloadScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
4885 "class Foo {\n"
4886 " int x = 4;\n"
4887 " int y = 5;\n"
4888 "}\n"
4889 "%s Foo value;\n"
4890 "main() {\n"
4891 " return 0;\n"
4892 "}\n",
4893 late_tag),
4894 std::free);
4895 // clang-format on
4896
4897 lib = TestCase::ReloadTestScript(kReloadScript.get());
4898 EXPECT_VALID(lib);
4899 EXPECT_EQ(0, SimpleInvoke(lib, "main"));
4900
4901 // Change y's initializer and check this new initializer is used.
4902 auto kReloadScript2 =
4904 "class Foo {\n"
4905 " int x = 4;\n"
4906 " int y = 6;\n"
4907 "}\n"
4908 "%s Foo value;\n"
4909 "main() {\n"
4910 " return value.y;\n"
4911 "}\n",
4912 late_tag),
4913 std::free);
4914
4915 lib = TestCase::ReloadTestScript(kReloadScript2.get());
4916 EXPECT_VALID(lib);
4917 EXPECT_EQ(6, SimpleInvoke(lib, "main"));
4918}
4919
4920TEST_CASE(IsolateReload_RunNewFieldInitializersLazyTransitive) {
4921 const char* late_tag = TestCase::LateTag();
4922 // clang-format off
4923 auto kScript =
4925 "int myInitialValue = 8 * 7;\n"
4926 "class Foo {\n"
4927 " int x = 4;\n"
4928 "}\n"
4929 "%s Foo value;\n"
4930 "%s Foo value1;\n"
4931 "main() {\n"
4932 " value = Foo();\n"
4933 " value1 = Foo();\n"
4934 " return value.x;\n"
4935 "}\n",
4936 late_tag, late_tag),
4937 std::free);
4938 // clang-format on
4939
4940 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
4941 EXPECT_VALID(lib);
4942 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
4943
4944 // Add the field y. Do not touch y.
4945 // clang-format off
4946 auto kReloadScript =
4948 "int myInitialValue = 8 * 7;\n"
4949 "class Foo {\n"
4950 " int x = 4;\n"
4951 " int y = myInitialValue++;\n"
4952 "}\n"
4953 "%s Foo value;\n"
4954 "%s Foo value1;\n"
4955 "main() {\n"
4956 " return '${myInitialValue}';\n"
4957 "}\n",
4958 late_tag, late_tag),
4959 std::free);
4960 // clang-format on
4961
4962 lib = TestCase::ReloadTestScript(kReloadScript.get());
4963 EXPECT_VALID(lib);
4964 EXPECT_STREQ("56", SimpleInvokeStr(lib, "main"));
4965
4966 // Reload again. Field y's getter still needs to keep for initialization even
4967 // though it is no longer new.
4968 // clang-format off
4969 auto kReloadScript2 = Utils::CStringUniquePtr(
4970 OS::SCreate(nullptr,
4971 "int myInitialValue = 8 * 7;\n"
4972 "class Foo {\n"
4973 " int x = 4;\n"
4974 " int y = myInitialValue++;\n"
4975 "}\n"
4976 "%s Foo value;\n"
4977 "%s Foo value1;\n"
4978 "main() {\n"
4979 " return '${myInitialValue} ${value.y} ${value1.y} "
4980 "${myInitialValue}';\n"
4981 "}\n",
4982 late_tag, late_tag),
4983 std::free);
4984 // clang-format on
4985
4986 lib = TestCase::ReloadTestScript(kReloadScript2.get());
4987 EXPECT_VALID(lib);
4988 // Verify that field initializers ran lazily.
4989 EXPECT_STREQ("56 56 57 58", SimpleInvokeStr(lib, "main"));
4990}
4991
4992TEST_CASE(IsolateReload_RunNewFieldInitializersThrows) {
4993 const char* late_tag = TestCase::LateTag();
4994 // clang-format off
4995 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
4996 "class Foo {\n"
4997 " int x = 4;\n"
4998 "}\n"
4999 "%s Foo value;\n"
5000 "main() {\n"
5001 " value = Foo();\n"
5002 " return value.x;\n"
5003 "}\n",
5004 late_tag),
5005 std::free);
5006 // clang-format on
5007
5008 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
5009 EXPECT_VALID(lib);
5010 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
5011
5012 // Add the field y.
5013 // clang-format off
5014 auto kReloadScript =
5016 "class Foo {\n"
5017 " int x = 4;\n"
5018 " int y = throw 'exception';\n"
5019 "}\n"
5020 "%s Foo value;\n"
5021 "main() {\n"
5022 " try {\n"
5023 " return value.y.toString();\n"
5024 " } catch (e) {\n"
5025 " return e.toString();\n"
5026 " }\n"
5027 "}\n",
5028 late_tag),
5029 std::free);
5030 // clang-format on
5031
5032 lib = TestCase::ReloadTestScript(kReloadScript.get());
5033 EXPECT_VALID(lib);
5034 // Verify that we ran field initializers on existing instances.
5035 EXPECT_STREQ("exception", SimpleInvokeStr(lib, "main"));
5036}
5037
5038TEST_CASE(IsolateReload_RunNewFieldInitializersCyclicInitialization) {
5039 const char* late_tag = TestCase::LateTag();
5040 // clang-format off
5041 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
5042 "class Foo {\n"
5043 " int x = 4;\n"
5044 "}\n"
5045 "%s Foo value;\n"
5046 "main() {\n"
5047 " value = Foo();\n"
5048 " return value.x;\n"
5049 "}\n",
5050 late_tag),
5051 std::free);
5052 // clang-format on
5053
5054 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
5055 EXPECT_VALID(lib);
5056 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
5057
5058 // Add the field y.
5059 // clang-format off
5060 auto kReloadScript =
5062 "class Foo {\n"
5063 " int x = 4;\n"
5064 " int y = value.y;\n"
5065 "}\n"
5066 "%s Foo value;\n"
5067 "main() {\n"
5068 " try {\n"
5069 " return value.y.toString();\n"
5070 " } catch (e) {\n"
5071 " return e.toString();\n"
5072 " }\n"
5073 "}\n",
5074 late_tag),
5075 std::free);
5076 // clang-format on
5077 lib = TestCase::ReloadTestScript(kReloadScript.get());
5078 EXPECT_VALID(lib);
5079 EXPECT_STREQ("Stack Overflow", SimpleInvokeStr(lib, "main"));
5080}
5081
5082// When an initializer expression has a syntax error, we detect it at reload
5083// time.
5084TEST_CASE(IsolateReload_RunNewFieldInitializersSyntaxError) {
5085 const char* late_tag = TestCase::LateTag();
5086 // clang-format off
5087 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
5088 "class Foo {\n"
5089 " int x = 4;\n"
5090 "}\n"
5091 "%s Foo value;\n"
5092 "main() {\n"
5093 " value = Foo();\n"
5094 " return value.x;\n"
5095 "}\n",
5096 late_tag),
5097 std::free);
5098 // clang-format on
5099
5100 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
5101 EXPECT_VALID(lib);
5102 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
5103
5104 // Add the field y with a syntax error in the initializing expression.
5105 // clang-format off
5106 auto kReloadScript =
5108 "class Foo {\n"
5109 " int x = 4;\n"
5110 " int y = ......;\n"
5111 "}\n"
5112 "%s Foo value;\n"
5113 "main() {\n"
5114 " return '${value.y == null}';"
5115 "}\n",
5116 late_tag),
5117 std::free);
5118 // clang-format on
5119
5120 // The reload fails because the initializing expression is parsed at
5121 // class finalization time.
5122 lib = TestCase::ReloadTestScript(kReloadScript.get());
5123 EXPECT_ERROR(lib, "...");
5124}
5125
5126// When an initializer expression has a syntax error, we detect it at reload
5127// time.
5128TEST_CASE(IsolateReload_RunNewFieldInitializersSyntaxError2) {
5129 const char* late_tag = TestCase::LateTag();
5130 // clang-format off
5131 auto kScript = Utils::CStringUniquePtr(
5132 OS::SCreate(nullptr,
5133 "class Foo {\n"
5134 " Foo() { /* default constructor */ }\n"
5135 " int x = 4;\n"
5136 "}\n"
5137 "%s Foo value;\n"
5138 "main() {\n"
5139 " value = Foo();\n"
5140 " return value.x;\n"
5141 "}\n",
5142 late_tag),
5143 std::free);
5144 // clang-format on
5145
5146 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
5147 EXPECT_VALID(lib);
5148 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
5149
5150 // Add the field y with a syntax error in the initializing expression.
5151 // clang-format off
5152 auto kReloadScript = Utils::CStringUniquePtr(
5153 OS::SCreate(nullptr,
5154 "class Foo {\n"
5155 " Foo() { /* default constructor */ }\n"
5156 " int x = 4;\n"
5157 " int y = ......;\n"
5158 "}\n"
5159 "%s Foo value;\n"
5160 "main() {\n"
5161 " return '${value.y == null}';"
5162 "}\n",
5163 late_tag),
5164 std::free);
5165 // clang-format on
5166
5167 // The reload fails because the initializing expression is parsed at
5168 // class finalization time.
5169 lib = TestCase::ReloadTestScript(kReloadScript.get());
5170 EXPECT_ERROR(lib, "...");
5171}
5172
5173// When an initializer expression has a syntax error, we detect it at reload
5174// time.
5175TEST_CASE(IsolateReload_RunNewFieldInitializersSyntaxError3) {
5176 const char* late_tag = TestCase::LateTag();
5177 // clang-format off
5178 auto kScript = Utils::CStringUniquePtr(
5179 OS::SCreate(nullptr,
5180 "class Foo {\n"
5181 " Foo() { /* default constructor */ }\n"
5182 " int x = 4;\n"
5183 "}\n"
5184 "%s Foo value;\n"
5185 "main() {\n"
5186 " value = Foo();\n"
5187 " return value.x;\n"
5188 "}\n",
5189 late_tag),
5190 std::free);
5191 // clang-format on
5192
5193 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
5194 EXPECT_VALID(lib);
5195 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
5196
5197 // Add the field y with a syntax error in the initializing expression.
5198 // clang-format off
5199 auto kReloadScript = Utils::CStringUniquePtr(
5200 OS::SCreate(nullptr,
5201 "class Foo {\n"
5202 " Foo() { /* default constructor */ }\n"
5203 " int x = 4;\n"
5204 " int y = ......\n"
5205 "}\n"
5206 "%s Foo value;\n"
5207 "main() {\n"
5208 " return '${value.y == null}';"
5209 "}\n",
5210 late_tag),
5211 std::free);
5212 // clang-format on
5213
5214 // The reload fails because the initializing expression is parsed at
5215 // class finalization time.
5216 lib = TestCase::ReloadTestScript(kReloadScript.get());
5217 EXPECT_ERROR(lib, "......");
5218}
5219
5220TEST_CASE(IsolateReload_RunNewFieldInitializersSuperClass) {
5221 const char* late_tag = TestCase::LateTag();
5222 // clang-format off
5223 auto kScript =
5225 "class Super {\n"
5226 " static var foo = 'right';\n"
5227 "}\n"
5228 "class Foo extends Super {\n"
5229 " static var foo = 'wrong';\n"
5230 "}\n"
5231 "%s Foo value;\n"
5232 "main() {\n"
5233 " Super.foo;\n"
5234 " Foo.foo;\n"
5235 " value = Foo();\n"
5236 " return 0;\n"
5237 "}\n",
5238 late_tag),
5239 std::free);
5240 // clang-format on
5241
5242 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
5243 EXPECT_VALID(lib);
5244 EXPECT_EQ(0, SimpleInvoke(lib, "main"));
5245
5246 // clang-format on
5247 auto kReloadScript =
5249 "class Super {\n"
5250 " static var foo = 'right';\n"
5251 " var newField = foo;\n"
5252 "}\n"
5253 "class Foo extends Super {\n"
5254 " static var foo = 'wrong';\n"
5255 "}\n"
5256 "%s Foo value;\n"
5257 "main() {\n"
5258 " return value.newField;\n"
5259 "}\n",
5260 late_tag),
5261 std::free);
5262 // clang-format off
5263
5264 lib = TestCase::ReloadTestScript(kReloadScript.get());
5265 EXPECT_VALID(lib);
5266 // Verify that we ran field initializers on existing instances in the
5267 // correct scope.
5268 const char* actual = SimpleInvokeStr(lib, "main");
5269 EXPECT(actual != nullptr);
5270 if (actual != nullptr) {
5271 EXPECT_STREQ("right", actual);
5272 }
5273}
5274
5275TEST_CASE(IsolateReload_RunNewFieldInitializersWithConsts) {
5276 const char* late_tag = TestCase::LateTag();
5277 // clang-format off
5278 auto kScript =
5280 "class C {\n"
5281 " final x;\n"
5282 " const C(this.x);\n"
5283 "}\n"
5284 "var a = const C(const C(1));\n"
5285 "var b = const C(const C(2));\n"
5286 "var c = const C(const C(3));\n"
5287 "var d = const C(const C(4));\n"
5288 "class Foo {\n"
5289 "}\n"
5290 "%s Foo value;\n"
5291 "main() {\n"
5292 " value = Foo();\n"
5293 " a; b; c; d;\n"
5294 " return 'Okay';\n"
5295 "}\n",
5296 late_tag),
5297 std::free);
5298 // clang-format on
5299
5300 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
5301 EXPECT_VALID(lib);
5302 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
5303
5304 // clang-format off
5305 auto kReloadScript = Utils::CStringUniquePtr(
5307 nullptr,
5308 "class C {\n"
5309 " final x;\n"
5310 " const C(this.x);\n"
5311 "}\n"
5312 "var a = const C(const C(1));\n"
5313 "var b = const C(const C(2));\n"
5314 "var c = const C(const C(3));\n"
5315 "var d = const C(const C(4));\n"
5316 "class Foo {\n"
5317 " var d = const C(const C(4));\n"
5318 " var c = const C(const C(3));\n"
5319 " var b = const C(const C(2));\n"
5320 " var a = const C(const C(1));\n"
5321 "}\n"
5322 "%s Foo value;\n"
5323 "main() {\n"
5324 " return '${identical(a, value.a)} ${identical(b, value.b)}'"
5325 " ' ${identical(c, value.c)} ${identical(d, value.d)}';\n"
5326 "}\n",
5327 late_tag),
5328 std::free);
5329 // clang-format on
5330 lib = TestCase::ReloadTestScript(kReloadScript.get());
5331 EXPECT_VALID(lib);
5332 // Verify that we ran field initializers on existing instances and the const
5333 // expressions were properly canonicalized.
5334 EXPECT_STREQ("true true true true", SimpleInvokeStr(lib, "main"));
5335}
5336
5337TEST_CASE(IsolateReload_RunNewFieldInitializersWithGenerics) {
5338 const char* nullable_tag = TestCase::NullableTag();
5339 const char* late_tag = TestCase::LateTag();
5340 // clang-format off
5341 auto kScript =
5343 "class Foo<T> {\n"
5344 " T%s x;\n"
5345 "}\n"
5346 "%s Foo value1;\n"
5347 "%s Foo value2;\n"
5348 "main() {\n"
5349 " value1 = Foo<String>();\n"
5350 " value2 = Foo<int>();\n"
5351 " return 'Okay';\n"
5352 "}\n",
5353 nullable_tag, late_tag, late_tag),
5354 std::free);
5355 // clang-format on
5356
5357 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
5358 EXPECT_VALID(lib);
5359 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
5360
5361 // clang-format off
5362 auto kReloadScript = Utils::CStringUniquePtr(
5363 OS::SCreate(nullptr,
5364 "class Foo<T> {\n"
5365 " T%s x;\n"
5366 " List<T> y = List<T>.empty();"
5367 " dynamic z = <T,T>{};"
5368 "}\n"
5369 "%s Foo value1;\n"
5370 "%s Foo value2;\n"
5371 "main() {\n"
5372 " return '${value1.y.runtimeType} ${value1.z.runtimeType}'"
5373 " ' ${value2.y.runtimeType} ${value2.z.runtimeType}';\n"
5374 "}\n",
5375 nullable_tag, late_tag, late_tag),
5376 std::free);
5377 // clang-format on
5378
5379 lib = TestCase::ReloadTestScript(kReloadScript.get());
5380 EXPECT_VALID(lib);
5381 // Verify that we ran field initializers on existing instances and
5382 // correct type arguments were used.
5383 EXPECT_STREQ("List<String> _Map<String, String> List<int> _Map<int, int>",
5384 SimpleInvokeStr(lib, "main"));
5385}
5386
5387TEST_CASE(IsolateReload_AddNewStaticField) {
5388 const char* kScript =
5389 "class C {\n"
5390 "}\n"
5391 "main() {\n"
5392 " return 'Okay';\n"
5393 "}\n";
5394
5395 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
5397 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
5399 const char* kReloadScript =
5400 "class C {\n"
5401 " static var x = 42;\n"
5402 "}\n"
5403 "main() {\n"
5404 " return '${C.x}';\n"
5405 "}\n";
5406
5407 lib = TestCase::ReloadTestScript(kReloadScript);
5408 EXPECT_VALID(lib);
5409 EXPECT_STREQ("42", SimpleInvokeStr(lib, "main"));
5410}
5412TEST_CASE(IsolateReload_StaticFieldInitialValueDoesnotChange) {
5413 const char* kScript =
5414 "class C {\n"
5415 " static var x = 42;\n"
5416 "}\n"
5417 "main() {\n"
5418 " return '${C.x}';\n"
5419 "}\n";
5420
5421 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
5422 EXPECT_VALID(lib);
5423 EXPECT_STREQ("42", SimpleInvokeStr(lib, "main"));
5424
5425 const char* kReloadScript =
5426 "class C {\n"
5427 " static var x = 13;\n"
5428 "}\n"
5429 "main() {\n"
5430 " return '${C.x}';\n"
5431 "}\n";
5432
5433 lib = TestCase::ReloadTestScript(kReloadScript);
5434 EXPECT_VALID(lib);
5435 // Newly loaded field maintained old static value
5436 EXPECT_STREQ("42", SimpleInvokeStr(lib, "main"));
5437}
5438
5439class CidCountingVisitor : public ObjectVisitor {
5440 public:
5441 explicit CidCountingVisitor(intptr_t cid) : cid_(cid) {}
5442 virtual ~CidCountingVisitor() {}
5443
5444 virtual void VisitObject(ObjectPtr obj) {
5445 if (obj->GetClassId() == cid_) {
5446 count_++;
5447 }
5448 }
5449
5450 intptr_t count() const { return count_; }
5451
5452 private:
5453 intptr_t cid_;
5454 intptr_t count_ = 0;
5455};
5456
5457TEST_CASE(IsolateReload_DeleteStaticField) {
5458 const char* kScript =
5459 "class C {\n"
5460 "}\n"
5461 "class Foo {\n"
5462 "static var x = C();\n"
5463 "}\n"
5464 "main() {\n"
5465 " return Foo.x;\n"
5466 "}\n";
5467
5468 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
5469 EXPECT_VALID(lib);
5470 intptr_t cid = 1118;
5471 {
5473 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
5475 {
5476 TransitionNativeToVM transition(thread);
5478 }
5480 }
5481
5482 const char* kReloadScript =
5483 "class C {\n"
5484 "}\n"
5485 "class Foo {\n"
5486 "}\n"
5487 "main() {\n"
5488 " return '${Foo()}';\n"
5489 "}\n";
5490
5491 lib = TestCase::ReloadTestScript(kReloadScript);
5492 EXPECT_VALID(lib);
5493 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
5495 {
5496 TransitionNativeToVM transition(thread);
5497 GCTestHelper::CollectAllGarbage();
5498
5499 {
5500 HeapIterationScope iteration(thread);
5501 CidCountingVisitor counting_visitor(cid);
5502 iteration.IterateObjects(&counting_visitor);
5503
5504 // We still expect to find references to static field values
5505 // because they are not deleted after hot reload.
5506 EXPECT_NE(counting_visitor.count(), 0);
5507 }
5508 }
5509}
5510
5511static void TestReloadWithFieldChange(const char* prefix,
5512 const char* suffix,
5513 const char* verify,
5514 const char* from_type,
5515 const char* from_init,
5516 const char* to_type,
5517 const char* to_init) {
5518 const char* late_tag = TestCase::LateTag();
5519 // clang-format off
5520 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
5521 R"(
5522 import 'dart:typed_data';
5523
5524 void doubleEq(double got, double expected) {
5525 if (got != expected) throw 'expected $expected got $got';
5526 }
5527
5528 void float32x4Eq(Float32x4 got, Float32x4 expected) {
5529 if (got.equal(expected).signMask != 0xf) throw 'expected $expected got $got';
5530 }
5531
5532 class Foo {
5533 %s
5534 %s x = %s;
5535 %s
5536 }
5537 %s Foo value;
5538 main() {
5539 value = Foo();
5540 %s
5541 return 'Okay';
5542 }
5543 )",
5544 prefix,
5545 from_type,
5546 from_init,
5547 suffix,
5548 late_tag,
5549 verify), std::free);
5550 // clang-format on
5551
5552 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
5553 EXPECT_VALID(lib);
5554 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
5555
5556 // clang-format off
5557 auto kReloadScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
5558 import 'dart:typed_data';
5559
5560 void doubleEq(double got, double expected) {
5561 if (got != expected) throw 'expected $expected got $got';
5562 }
5563
5564 void float32x4Eq(Float32x4 got, Float32x4 expected) {
5565 if (got.equal(expected).signMask != 0xf) throw 'expected $expected got $got';
5566 }
5567
5568 class Foo {
5569 %s
5570 %s x = %s;
5571 %s
5572 }
5573 %s Foo value;
5574 main() {
5575 try {
5577 return value.x.toString();
5578 } catch (e) {
5579 return e.toString();
5580 }
5581 }
5582 )", prefix, to_type, to_init, suffix,
5583 late_tag, verify), std::free);
5584 // clang-format on
5585
5586 lib = TestCase::ReloadTestScript(kReloadScript.get());
5587 EXPECT_VALID(lib);
5588 EXPECT_STREQ(
5590 Thread::Current()->zone(),
5591 "type '%s' is not a subtype of type '%s' of 'function result'",
5592 from_type, to_type),
5593 SimpleInvokeStr(lib, "main"));
5594}
5595
5596TEST_CASE(IsolateReload_ExistingFieldChangesType) {
5597 TestReloadWithFieldChange(/*prefix=*/"", /*suffix=*/"", /*verify=*/"",
5598 /*from_type=*/"int", /*from_init=*/"42",
5599 /*to_type=*/"double", /*to_init=*/"42.0");
5600}
5601
5602TEST_CASE(IsolateReload_ExistingFieldChangesTypeWithOtherUnboxedFields) {
5604 /*prefix=*/"double a = 1.5;",
5605 /*suffix=*/"Float32x4 b = Float32x4(1.0, 2.0, 3.0, 4.0);", /*verify=*/
5606 "doubleEq(value.a, 1.5); float32x4Eq(value.b, Float32x4(1.0, 2.0, 3.0, "
5607 "4.0));",
5608 /*from_type=*/"int", /*from_init=*/"42", /*to_type=*/"double",
5609 /*to_init=*/"42.0");
5610}
5611
5612TEST_CASE(IsolateReload_ExistingFieldUnboxedToBoxed) {
5614 /*prefix=*/"double a = 1.5;",
5615 /*suffix=*/"Float32x4 b = Float32x4(1.0, 2.0, 3.0, 4.0);", /*verify=*/
5616 "doubleEq(value.a, 1.5); float32x4Eq(value.b, Float32x4(1.0, 2.0, 3.0, "
5617 "4.0));",
5618 /*from_type=*/"double", /*from_init=*/"42.0", /*to_type=*/"String",
5619 /*to_init=*/"'42'");
5620}
5621
5622TEST_CASE(IsolateReload_ExistingFieldBoxedToUnboxed) {
5623 // Note: underlying field will not actually be unboxed.
5625 /*prefix=*/"double a = 1.5;",
5626 /*suffix=*/"Float32x4 b = Float32x4(1.0, 2.0, 3.0, 4.0);", /*verify=*/
5627 "doubleEq(value.a, 1.5); float32x4Eq(value.b, Float32x4(1.0, 2.0, 3.0, "
5628 "4.0));",
5629 /*from_type=*/"String", /*from_init=*/"'42.0'", /*to_type=*/"double",
5630 /*to_init=*/"42.0");
5631}
5632
5633TEST_CASE(IsolateReload_ExistingFieldUnboxedToUnboxed) {
5634 // Note: underlying field will not actually be unboxed.
5636 /*prefix=*/"double a = 1.5;",
5637 /*suffix=*/"Float32x4 b = Float32x4(1.0, 2.0, 3.0, 4.0);", /*verify=*/
5638 "doubleEq(value.a, 1.5); float32x4Eq(value.b, Float32x4(1.0, 2.0, 3.0, "
5639 "4.0));",
5640 /*from_type=*/"double", /*from_init=*/"42.0", /*to_type=*/"Float32x4",
5641 /*to_init=*/"Float32x4(1.0, 2.0, 3.0, 4.0)");
5642}
5643
5644TEST_CASE(IsolateReload_ExistingStaticFieldChangesType) {
5645 const char* kScript = R"(
5646 int value = init();
5647 init() => 42;
5648 main() {
5649 return value.toString();
5650 }
5651 )";
5652
5653 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
5654 EXPECT_VALID(lib);
5655 EXPECT_STREQ("42", SimpleInvokeStr(lib, "main"));
5657 const char* kReloadScript = R"(
5658 double value = init();
5659 init() => 42.0;
5660 main() {
5661 try {
5662 return value.toString();
5663 } catch (e) {
5664 return e.toString();
5665 }
5666 }
5667 )";
5668
5669 lib = TestCase::ReloadTestScript(kReloadScript);
5670 EXPECT_VALID(lib);
5671 EXPECT_STREQ(
5672 "type 'int' is not a subtype of type 'double' of 'function result'",
5673 SimpleInvokeStr(lib, "main"));
5674}
5675
5676TEST_CASE(IsolateReload_ExistingFieldChangesTypeIndirect) {
5677 const char* late_tag = TestCase::LateTag();
5678 // clang-format off
5679 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
5680 class A {}
5681 class B extends A {}
5682 class Foo {
5683 A x;
5684 Foo(this.x);
5685 }
5686 %s Foo value;
5687 main() {
5688 value = Foo(B());
5689 return 'Okay';
5690 }
5691 )", late_tag), std::free);
5692 // clang-format on
5693
5694 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
5695 EXPECT_VALID(lib);
5696 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
5697
5698 // B is no longer a subtype of A.
5699 // clang-format off
5700 auto kReloadScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
5701 class A {}
5702 class B {}
5703 class Foo {
5704 A x;
5705 Foo(this.x);
5706 }
5707 %s Foo value;
5708 main() {
5709 try {
5710 return value.x.toString();
5711 } catch (e) {
5712 return e.toString();
5713 }
5714 }
5715 )", late_tag), std::free);
5716 // clang-format on
5717
5718 lib = TestCase::ReloadTestScript(kReloadScript.get());
5719 EXPECT_VALID(lib);
5720 EXPECT_STREQ("type 'B' is not a subtype of type 'A' of 'function result'",
5721 SimpleInvokeStr(lib, "main"));
5722}
5723
5724TEST_CASE(IsolateReload_ExistingStaticFieldChangesTypeIndirect) {
5725 const char* kScript = R"(
5726 class A {}
5727 class B extends A {}
5728 A value = init();
5729 init() => new B();
5730 main() {
5731 return value.toString();
5732 }
5733 )";
5734
5735 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
5736 EXPECT_VALID(lib);
5737 EXPECT_STREQ("Instance of 'B'", SimpleInvokeStr(lib, "main"));
5738
5739 // B is no longer a subtype of A.
5740 const char* kReloadScript = R"(
5741 class A {}
5742 class B {}
5743 A value = init();
5744 init() => new A();
5745 main() {
5746 try {
5747 return value.toString();
5748 } catch (e) {
5749 return e.toString();
5750 }
5751 }
5752 )";
5753
5754 lib = TestCase::ReloadTestScript(kReloadScript);
5755 EXPECT_VALID(lib);
5756 EXPECT_STREQ("type 'B' is not a subtype of type 'A' of 'function result'",
5757 SimpleInvokeStr(lib, "main"));
5758}
5759
5760TEST_CASE(IsolateReload_ExistingFieldChangesTypeIndirectGeneric) {
5761 const char* late_tag = TestCase::LateTag();
5762 // clang-format off
5763 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
5764 class A {}
5765 class B extends A {}
5766 class Foo {
5767 List<A> x;
5768 Foo(this.x);
5769 }
5770 %s Foo value;
5771 main() {
5772 value = Foo(List<B>.empty());
5773 return 'Okay';
5774 }
5775 )", late_tag), std::free);
5776 // clang-format on
5777
5778 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
5779 EXPECT_VALID(lib);
5780 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
5781
5782 // B is no longer a subtype of A.
5783 // clang-format off
5784 auto kReloadScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
5785 class A {}
5786 class B {}
5787 class Foo {
5788 List<A> x;
5789 Foo(this.x);
5790 }
5791 %s Foo value;
5792 main() {
5793 try {
5794 return value.x.toString();
5795 } catch (e) {
5796 return e.toString();
5797 }
5798 }
5799 )", late_tag), std::free);
5800 // clang-format on
5801
5802 lib = TestCase::ReloadTestScript(kReloadScript.get());
5803 EXPECT_VALID(lib);
5804 EXPECT_STREQ(
5805 "type 'List<B>' is not a subtype of type 'List<A>' of 'function result'",
5806 SimpleInvokeStr(lib, "main"));
5807}
5808
5809TEST_CASE(IsolateReload_ExistingStaticFieldChangesTypeIndirectGeneric) {
5810 const char* kScript = R"(
5811 class A {}
5812 class B extends A {}
5813 List<A> value = init();
5814 init() => List<B>.empty();
5815 main() {
5816 return value.toString();
5817 }
5818 )";
5819
5820 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
5821 EXPECT_VALID(lib);
5822 EXPECT_STREQ("[]", SimpleInvokeStr(lib, "main"));
5823
5824 // B is no longer a subtype of A.
5825 const char* kReloadScript = R"(
5826 class A {}
5827 class B {}
5828 List<A> value = init();
5829 init() => List<A>.empty();
5830 main() {
5831 try {
5832 return value.toString();
5833 } catch (e) {
5834 return e.toString();
5835 }
5836 }
5837 )";
5838
5839 lib = TestCase::ReloadTestScript(kReloadScript);
5840 EXPECT_VALID(lib);
5841 EXPECT_STREQ(
5842 "type 'List<B>' is not a subtype of type 'List<A>' of 'function result'",
5843 SimpleInvokeStr(lib, "main"));
5844}
5845
5846TEST_CASE(IsolateReload_ExistingFieldChangesTypeIndirectFunction) {
5847 const char* late_tag = TestCase::LateTag();
5848 // clang-format off
5849 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
5850 class A {}
5851 class B extends A {}
5852 typedef bool Predicate(B b);
5853 class Foo {
5854 Predicate x;
5855 Foo(this.x);
5856 }
5857 %s Foo value;
5858 main() {
5859 value = Foo((A a) => true);
5860 return 'Okay';
5861 }
5862 )", late_tag), std::free);
5863 // clang-format on
5864
5865 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
5866 EXPECT_VALID(lib);
5867 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
5868
5869 // B is no longer a subtype of A.
5870 // clang-format off
5871 auto kReloadScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
5872 class A {}
5873 class B {}
5874 typedef bool Predicate(B b);
5875 class Foo {
5876 Predicate x;
5877 Foo(this.x);
5878 }
5879 %s Foo value;
5880 main() {
5881 try {
5882 return value.x.toString();
5883 } catch (e) {
5884 return e.toString();
5885 }
5886 }
5887 )", late_tag), std::free);
5888 // clang-format on
5889
5890 lib = TestCase::ReloadTestScript(kReloadScript.get());
5891 EXPECT_VALID(lib);
5892 EXPECT_STREQ(
5893 "type '(A) => bool' is not a subtype of type '(B) => bool' of 'function "
5894 "result'",
5895 SimpleInvokeStr(lib, "main"));
5897
5898TEST_CASE(IsolateReload_ExistingStaticFieldChangesTypeIndirectFunction) {
5899 const char* kScript = R"(
5900 class A {}
5901 class B extends A {}
5902 typedef bool Predicate(B b);
5903 Predicate value = init();
5904 init() => (A a) => true;
5905 main() {
5906 return value.toString();
5907 }
5908 )";
5909
5910 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
5911 EXPECT_VALID(lib);
5912 EXPECT_STREQ("Closure: (A) => bool", SimpleInvokeStr(lib, "main"));
5913
5914 // B is no longer a subtype of A.
5915 const char* kReloadScript = R"(
5916 class A {}
5917 class B {}
5918 typedef bool Predicate(B b);
5919 Predicate value = init();
5920 init() => (B a) => true;
5921 main() {
5922 try {
5923 return value.toString();
5924 } catch (e) {
5925 return e.toString();
5926 }
5927 }
5928 )";
5929
5930 lib = TestCase::ReloadTestScript(kReloadScript);
5931 EXPECT_VALID(lib);
5932 EXPECT_STREQ(
5933 "type '(A) => bool' is not a subtype of type '(B) => bool' of 'function "
5934 "result'",
5935 SimpleInvokeStr(lib, "main"));
5936}
5937
5938TEST_CASE(IsolateReload_TypedefToNotTypedef) {
5939 // The CFE lowers typedefs to function types and as such the VM will not see
5940 // any name collision between a class and a typedef class (which doesn't exist
5941 // anymore).
5942 const char* kScript =
5943 "typedef bool Predicate(dynamic x);\n"
5944 "main() {\n"
5945 " return (42 is Predicate).toString();\n"
5946 "}\n";
5947
5948 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
5949 EXPECT_VALID(lib);
5950 EXPECT_STREQ("false", SimpleInvokeStr(lib, "main"));
5951
5952 const char* kReloadScript =
5953 "class Predicate {\n"
5954 " bool call(dynamic x) { return false; }\n"
5955 "}\n"
5956 "main() {\n"
5957 " return (42 is Predicate).toString();\n"
5958 "}\n";
5959
5962}
5963
5964TEST_CASE(IsolateReload_NotTypedefToTypedef) {
5965 const char* kScript =
5966 "class Predicate {\n"
5967 " bool call(dynamic x) { return false; }\n"
5968 "}\n"
5969 "main() {\n"
5970 " return (42 is Predicate).toString();\n"
5971 "}\n";
5972
5973 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
5974 EXPECT_VALID(lib);
5975 EXPECT_STREQ("false", SimpleInvokeStr(lib, "main"));
5976
5977 // The CFE lowers typedefs to function types and as such the VM will not see
5978 // any name collision between a class and a typedef class (which doesn't exist
5979 // anymore).
5980 const char* kReloadScript =
5981 "typedef bool Predicate(dynamic x);\n"
5982 "main() {\n"
5983 " return (42 is Predicate).toString();\n"
5984 "}\n";
5985
5988}
5989
5990TEST_CASE(IsolateReload_TypedefAddParameter) {
5991 const char* kScript =
5992 "typedef bool Predicate(dynamic x);\n"
5993 "main() {\n"
5994 " bool foo(x) => true;\n"
5995 " return (foo is Predicate).toString();\n"
5996 "}\n";
5997
5998 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
5999 EXPECT_VALID(lib);
6000 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
6001
6002 const char* kReloadScript =
6003 "typedef bool Predicate(dynamic x, dynamic y);\n"
6004 "main() {\n"
6005 " bool foo(x) => true;\n"
6006 " return (foo is Predicate).toString();\n"
6007 "}\n";
6008
6011 EXPECT_STREQ("false", SimpleInvokeStr(lib, "main"));
6012}
6013
6014TEST_CASE(IsolateReload_PatchStaticInitializerWithClosure) {
6015 const char* kScript =
6016 "dynamic field = (a) => 'a$a';\n"
6017 "main() {\n"
6018 " dynamic f = field;\n"
6019 " return f('b');\n"
6020 "}\n";
6021
6022 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
6023 EXPECT_VALID(lib);
6024 EXPECT_STREQ("ab", SimpleInvokeStr(lib, "main"));
6025
6026 const char* kReloadScript =
6027 "extraFunction() => 'Just here to change kernel offsets';\n"
6028 "dynamic field = (_, __) => 'Not executed';\n"
6029 "main() {\n"
6030 " dynamic f = field;\n"
6031 " return f('c');\n"
6032 "}\n";
6033
6034 lib = TestCase::ReloadTestScript(kReloadScript);
6035 EXPECT_VALID(lib);
6036 EXPECT_STREQ("ac", SimpleInvokeStr(lib, "main"));
6037}
6038
6039TEST_CASE(IsolateReload_StaticTargetArityChange) {
6040 const char* kScript = R"(
6041 class A {
6042 final x;
6043 final y;
6044 const A(this.x, this.y);
6045 }
6046
6047 dynamic closure;
6048
6049 main() {
6050 closure = () => A(1, 2);
6051 return "okay";
6052 }
6053 )";
6054
6055 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
6056 EXPECT_VALID(lib);
6057 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
6058
6059 const char* kReloadScript = R"(
6060 class A {
6061 final x;
6062 const A(this.x);
6063 }
6064
6065 dynamic closure;
6066
6067 main() {
6068 // Call the old closure, which will try to call A(1, 2).
6069 closure();
6070
6071 return "okay";
6072 }
6073 )";
6074
6075 lib = TestCase::ReloadTestScript(kReloadScript);
6076 EXPECT_VALID(lib);
6077 EXPECT_ERROR(SimpleInvokeError(lib, "main"),
6078 "Unhandled exception:\n"
6079 "NoSuchMethodError: No constructor 'A.' "
6080 "with matching arguments declared in class 'A'.");
6081}
6082
6083TEST_CASE(IsolateReload_SuperGetterReboundToMethod) {
6084 const char* kScript = R"(
6085 import 'file:///test:isolate_reload_helper';
6086
6087 class A {
6088 get x => "123";
6089 }
6090
6091 class B extends A {
6092 f() {
6093 var old_x = super.x;
6094 reloadTest();
6095 var new_x = super.x;
6096 return "$old_x:$new_x";
6097 }
6098 }
6099
6100 main() {
6101 return B().f().toString();
6102 }
6103 )";
6104
6105 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
6106 EXPECT_VALID(lib);
6107
6108 const char* kReloadScript = R"(
6109 import 'file:///test:isolate_reload_helper';
6110
6111 class A {
6112 x() => "123";
6113 }
6114
6115 class B extends A {
6116 f() {
6117 var old_x = super.x;
6118 reloadTest();
6119 var new_x = super.x;
6120 return "$old_x:$new_x";
6121 }
6122 }
6123
6124 main() {
6125 return B().f();
6126 }
6127 )";
6128
6130
6131 EXPECT_STREQ("123:Closure: () => dynamic from Function 'x':.",
6132 SimpleInvokeStr(lib, "main"));
6133}
6134
6135// Regression test for b/179030011: incorrect lifetime management when reloading
6136// with multicomponent Kernel binary. When loading kernel blobs through tag
6137// handler (Dart_kKernelTag) we need to make sure to preserve a link between
6138// KernelProgramInfo objects and original typed data, because it might be
6139// coming with a finalizer, which otherwise might end up being called
6140// prematurely.
6141namespace {
6142
6143// Compile the given |source| to Kernel binary.
6144static void CompileToKernel(Dart_SourceFile source,
6145 const uint8_t** kernel_buffer,
6146 intptr_t* kernel_buffer_size) {
6147 Dart_SourceFile sources[] = {source};
6149 sources[0].uri, ARRAY_SIZE(sources), sources, kernel_buffer,
6150 kernel_buffer_size,
6151 /*incrementally=*/false);
6152 EXPECT(error == nullptr);
6153 EXPECT_NOTNULL(kernel_buffer);
6154}
6155
6156// LibraryTagHandler which returns a fixed Kernel binary back every time it
6157// receives a Dart_kKernelTag request. The binary is wrapped in an external
6158// typed data with a finalizer attached to it. If this finalizer is called
6159// it will set |was_finalized_| to true.
6160class KernelTagHandler {
6161 public:
6162 KernelTagHandler(uint8_t* kernel_buffer, intptr_t kernel_buffer_size)
6163 : kernel_buffer_(kernel_buffer), kernel_buffer_size_(kernel_buffer_size) {
6165 instance_ = this;
6166 }
6167
6168 ~KernelTagHandler() {
6170 instance_ = nullptr;
6171 }
6172
6173 static KernelTagHandler* Current() { return instance_; }
6174
6175 bool was_called() const { return was_called_; }
6176 bool was_finalized() const { return was_finalized_; }
6177
6178 private:
6179 static void Finalizer(void* isolate_callback_data, void* peer) {
6180 if (auto handler = KernelTagHandler::Current()) {
6181 handler->was_finalized_ = true;
6182 }
6183 }
6184
6186 Dart_Handle library,
6187 Dart_Handle url) {
6188 if (tag == Dart_kKernelTag) {
6189 auto handler = KernelTagHandler::Current();
6190 handler->was_called_ = true;
6191
6193 Dart_TypedData_kUint8, handler->kernel_buffer_,
6194 handler->kernel_buffer_size_);
6195 Dart_NewFinalizableHandle(result, handler->kernel_buffer_,
6196 handler->kernel_buffer_size_, &Finalizer);
6197 return result;
6198 }
6199 UNREACHABLE();
6200 return Dart_Null();
6201 }
6202
6203 static KernelTagHandler* instance_;
6204 uint8_t* kernel_buffer_;
6205 intptr_t kernel_buffer_size_;
6206 bool was_finalized_ = false;
6207 bool was_called_ = false;
6208};
6209
6210KernelTagHandler* KernelTagHandler::instance_ = nullptr;
6211} // namespace
6213TEST_CASE(IsolateReload_RegressB179030011) {
6214 struct Component {
6216 const uint8_t* kernel_buffer;
6217 intptr_t kernel_buffer_size;
6218 };
6219
6220 // clang-format off
6221 std::array<Component, 2> components = {{
6222 {{
6223 "file:///test-app",
6224 R"(
6225 class A {}
6226 void main() {
6227 A();
6228 }
6229 )"
6230 }, nullptr, 0},
6231 {{
6232 "file:///library",
6233 R"(
6234 class B {}
6235 )"
6236 }, nullptr, 0}
6237 }};
6238 // clang-format on
6239
6240 for (auto& component : components) {
6241 CompileToKernel(component.source, &component.kernel_buffer,
6242 &component.kernel_buffer_size);
6243 TestCaseBase::AddToKernelBuffers(component.kernel_buffer);
6244 }
6245
6246 // Concatenate all components.
6247 intptr_t kernel_buffer_size = 0;
6248 for (auto component : components) {
6249 kernel_buffer_size += component.kernel_buffer_size;
6250 }
6251 uint8_t* kernel_buffer = static_cast<uint8_t*>(malloc(kernel_buffer_size));
6252 TestCaseBase::AddToKernelBuffers(kernel_buffer);
6253 intptr_t pos = 0;
6254 for (auto component : components) {
6255 memcpy(kernel_buffer + pos, component.kernel_buffer, // NOLINT
6256 component.kernel_buffer_size);
6257 pos += component.kernel_buffer_size;
6258 }
6259
6260 // Load the first component into the isolate (to have something set as
6261 // root library).
6263 components[0].kernel_buffer, components[0].kernel_buffer_size);
6264 EXPECT_VALID(lib);
6266
6267 {
6268 KernelTagHandler handler(kernel_buffer, kernel_buffer_size);
6269 {
6270 // Additional API scope to prevent handles leaking into outer scope.
6272 // root_script_url does not really matter.
6273 TestCase::TriggerReload(/*root_script_url=*/"something.dill");
6275 }
6276 EXPECT(handler.was_called());
6277
6278 // Check that triggering GC does not cause finalizer registered by
6279 // tag handler to fire - meaning that kernel binary continues to live.
6280 TransitionNativeToVM transition(thread);
6281 GCTestHelper::CollectAllGarbage();
6282 EXPECT(!handler.was_finalized());
6283 }
6284}
6285
6286// Regression test for https://github.com/dart-lang/sdk/issues/50148.
6287TEST_CASE(IsolateReload_GenericConstructorTearOff) {
6288 const char* kScript = R"(
6289 typedef Create<T, R> = T Function(R ref);
6290
6291 class Base<Input> {
6292 Base(void Function(Create<void, Input> create) factory) : _factory = factory;
6293
6294 final void Function(Create<void, Input> create) _factory;
6295
6296 void fn() => _factory((ref) {});
6297 }
6298
6299 class Check<T> {
6300 Check(Create<Object?, List<T>> create);
6301 }
6302
6303 final f = Base<List<int>>(Check<int>.new);
6304
6305 main() {
6306 f.fn();
6307 return "okay";
6308 }
6309 )";
6310
6311 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
6312 EXPECT_VALID(lib);
6313 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
6314
6315 lib = TestCase::ReloadTestScript(kScript);
6316 EXPECT_VALID(lib);
6317 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
6318}
6319
6320// Regression test for https://github.com/dart-lang/sdk/issues/51215.
6321TEST_CASE(IsolateReload_ImplicitGetterWithLoadGuard) {
6322 const char* kLibScript = R"(
6323 import 'file:///test:isolate_reload_helper';
6324
6325 class A {
6326 int x;
6327 A(this.x);
6328 A.withUinitializedObject(int Function() callback) : x = callback();
6329 }
6331 A a = A(3);
6332
6333 main() {
6334 int sum = 0;
6335 // Trigger OSR and optimize this function.
6336 for (int i = 0; i < 30000; ++i) {
6337 sum += i;
6338 }
6339 // Make sure A.get:x is compiled.
6340 int y = a.x;
6341 // Reload while having an uninitialized
6342 // object A on the stack. This should result in
6343 // a load guard for A.x.
6344 A.withUinitializedObject(() {
6345 reloadTest();
6346 return 4;
6347 });
6348 // Trigger OSR and optimize this function once again.
6349 for (int i = 0; i < 30000; ++i) {
6350 sum += i;
6351 }
6352 // Trigger deoptimization in A.get:x.
6353 // It should correctly deoptimize into an implicit
6354 // getter with a load guard.
6355 a.x = 0x8070605040302010;
6356 int z = a.x & 0xffff;
6357 return "y: $y, z: $z";
6358 }
6359 )";
6360
6361 Dart_Handle lib1 =
6362 TestCase::LoadTestLibrary("test_lib1.dart", kLibScript, nullptr);
6363 EXPECT_VALID(lib1);
6364
6365 const char* kMainScript = R"(
6366 main() {}
6367 )";
6368
6369 // Trigger hot reload during execution of 'main' from test_lib1
6370 // without reloading test_lib1, so its unoptimized code is retained.
6371 EXPECT_VALID(TestCase::LoadTestScript(kMainScript, nullptr));
6373
6374 EXPECT_STREQ("y: 3, z: 8208", SimpleInvokeStr(lib1, "main"));
6375}
6376
6377// Regression test for https://github.com/dart-lang/sdk/issues/51835
6378TEST_CASE(IsolateReload_EnumInMainLibraryModified) {
6379 const char* kScript =
6380 "enum Bar { bar }\n"
6381 "class Foo { int? a; toString() => 'foo'; }"
6382 "main() {\n"
6383 " return Foo().toString();\n"
6384 "}\n";
6385
6386 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
6387 EXPECT_VALID(lib);
6389 EXPECT_STREQ("foo", SimpleInvokeStr(lib, "main"));
6390
6391 const char* kReloadScript =
6392 "enum Bar { bar }\n"
6393 "class Foo { int? a; String? b; toString() => 'foo'; }"
6394 "main() {\n"
6395 " return Foo().toString();\n"
6396 "}\n";
6397
6398 lib = TestCase::ReloadTestScript(kReloadScript);
6399 EXPECT_VALID(lib);
6400
6401 // Modification of an imported library propagates to the importing library.
6402 EXPECT_STREQ("foo", SimpleInvokeStr(lib, "main"));
6403}
6404
6405TEST_CASE(IsolateReload_KeepPragma1) {
6406 // Old version of closure function bar() has a pragma.
6407 const char* kScript =
6408 "import 'file:///test:isolate_reload_helper';\n"
6409 "foo() {\n"
6410 " @pragma('vm:prefer-inline')\n"
6411 " void bar() {}\n"
6412 " return bar;\n"
6413 "}"
6414 "main() {\n"
6415 " reloadTest();\n"
6416 "}\n";
6417
6418 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
6419 EXPECT_VALID(lib);
6420
6421 // New version of closure function bar() doesn't have a pragma.
6422 const char* kReloadScript =
6423 "import 'file:///test:isolate_reload_helper';\n"
6424 "foo() {\n"
6425 " void bar() {}\n"
6426 " return bar;\n"
6427 "}"
6428 "main() {\n"
6429 " reloadTest();\n"
6430 "}\n";
6431
6433
6434 Dart_Handle foo1_result = Dart_Invoke(lib, NewString("foo"), 0, nullptr);
6435 EXPECT_VALID(foo1_result);
6436
6437 EXPECT_VALID(Dart_Invoke(lib, NewString("main"), 0, nullptr));
6438
6439 Dart_Handle foo2_result = Dart_Invoke(lib, NewString("foo"), 0, nullptr);
6440 EXPECT_VALID(foo2_result);
6441
6442 TransitionNativeToVM transition(thread);
6443 const auto& bar1 = Function::Handle(
6445 .function());
6446 const auto& bar2 = Function::Handle(
6448 .function());
6449 // Pragma should be retained on the old function,
6450 // and should not appear on the new function.
6451 EXPECT(Library::FindPragma(thread, /*only_core=*/false, bar1,
6452 Symbols::vm_prefer_inline()));
6453 EXPECT(!Library::FindPragma(thread, /*only_core=*/false, bar2,
6454 Symbols::vm_prefer_inline()));
6456
6457TEST_CASE(IsolateReload_EnumWithSet) {
6458 const char* kScript =
6459 "enum Enum1 {\n"
6460 " member1({Enum2.member1, Enum2.member2}),\n"
6461 " member2({Enum2.member2}),\n"
6462 " member3({Enum2.member1}),\n"
6463 " member4({Enum2.member2, Enum2.member1}),\n"
6464 " member5({Enum2.member1}),\n"
6465 " member6({Enum2.member1});\n"
6466 " const Enum1(this.set);\n"
6467 " final Set<Enum2> set;\n"
6468 "}\n"
6469 "enum Enum2 { member1, member2; }\n"
6470 "var retained;\n"
6471 "main() {\n"
6472 " retained = Enum1.member4;\n"
6473 " return 'ok';\n"
6474 "}\n";
6475 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
6476 EXPECT_VALID(lib);
6477 EXPECT_STREQ("ok", SimpleInvokeStr(lib, "main"));
6478
6479 const char* kReloadScript =
6480 "enum Enum2 { member1, member2; }\n"
6481 "enum Enum1 {\n"
6482 " member1({Enum2.member1, Enum2.member2}),\n"
6483 " member2({Enum2.member2}),\n"
6484 " member3({Enum2.member1}),\n"
6485 " member4({Enum2.member2, Enum2.member1}),\n"
6486 " member5({Enum2.member1}),\n"
6487 " member6({Enum2.member1});\n"
6488 " const Enum1(this.set);\n"
6489 " final Set<Enum2> set;\n"
6490 "}\n"
6491 "var retained;\n"
6492 "foo(e) {\n"
6493 " return switch (e as Enum1) {\n"
6494 " Enum1.member1 => \"a\",\n"
6495 " Enum1.member2 => \"b\",\n"
6496 " Enum1.member3 => \"c\",\n"
6497 " Enum1.member4 => \"d\",\n"
6498 " Enum1.member5 => \"e\",\n"
6499 " Enum1.member6 => \"f\",\n"
6500 " };\n"
6501 "}\n"
6502 "main() {\n"
6503 " return foo(retained);\n"
6504 "}\n";
6505
6506 lib = TestCase::ReloadTestScript(kReloadScript);
6507 EXPECT_VALID(lib);
6508
6509 {
6510 // Reset the cache to make kernel constant reading happen again and perform
6511 // fresh canonicalization, in particular the constants used by the switch
6512 // statement. Something about the reproduction in
6513 // https://github.com/dart-lang/sdk/issues/55350 causes this happen,
6514 // possibly something about the library dependency graph keeps the
6515 // equivalent enum use in a something with a separate kernel program info
6516 // such that execution after reload already has an empty cache.
6517 TransitionNativeToVM transition(thread);
6521 Array& constants = Array::Handle(info.constants());
6522 for (intptr_t i = 0; i < constants.Length(); i++) {
6523 constants.SetAt(i, Object::sentinel());
6524 }
6525 }
6526
6527 EXPECT_STREQ("d", SimpleInvokeStr(lib, "main"));
6528}
6529
6530TEST_CASE(IsolateReload_KeepPragma2) {
6531 // Old version of closure function bar() has a pragma.
6532 const char* kScript =
6533 "import 'file:///test:isolate_reload_helper';\n"
6534 "foo() {\n"
6535 " @pragma('vm:prefer-inline')\n"
6536 " void bar() {}\n"
6537 " return bar;\n"
6538 "}"
6539 "main() {\n"
6540 " reloadTest();\n"
6541 "}\n";
6542
6543 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
6544 EXPECT_VALID(lib);
6545
6546 // New version of closure function bar() has a different pragma.
6547 const char* kReloadScript =
6548 "import 'file:///test:isolate_reload_helper';\n"
6549 "foo() {\n"
6550 " @pragma('vm:never-inline')\n"
6551 " void bar() {}\n"
6552 " return bar;\n"
6553 "}"
6554 "main() {\n"
6555 " reloadTest();\n"
6556 "}\n";
6557
6559
6560 Dart_Handle foo1_result = Dart_Invoke(lib, NewString("foo"), 0, nullptr);
6561 EXPECT_VALID(foo1_result);
6562
6563 EXPECT_VALID(Dart_Invoke(lib, NewString("main"), 0, nullptr));
6564
6565 Dart_Handle foo2_result = Dart_Invoke(lib, NewString("foo"), 0, nullptr);
6566 EXPECT_VALID(foo2_result);
6567
6568 TransitionNativeToVM transition(thread);
6569 const auto& bar1 = Function::Handle(
6571 .function());
6572 const auto& bar2 = Function::Handle(
6574 .function());
6575 EXPECT(Library::FindPragma(thread, /*only_core=*/false, bar1,
6576 Symbols::vm_prefer_inline()));
6577 EXPECT(!Library::FindPragma(thread, /*only_core=*/false, bar1,
6578 Symbols::vm_never_inline()));
6579 EXPECT(!Library::FindPragma(thread, /*only_core=*/false, bar2,
6580 Symbols::vm_prefer_inline()));
6581 EXPECT(Library::FindPragma(thread, /*only_core=*/false, bar2,
6582 Symbols::vm_never_inline()));
6583}
6584
6585TEST_CASE(IsolateReload_KeepPragma3) {
6586 // Old version of closure function bar() doesn't have a pragma.
6587 const char* kScript =
6588 "import 'file:///test:isolate_reload_helper';\n"
6589 "foo() {\n"
6590 " void bar() {}\n"
6591 " return bar;\n"
6592 "}"
6593 "main() {\n"
6594 " reloadTest();\n"
6595 "}\n";
6596
6597 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
6598 EXPECT_VALID(lib);
6599
6600 // New version of closure function bar() has a pragma.
6601 const char* kReloadScript =
6602 "import 'file:///test:isolate_reload_helper';\n"
6603 "foo() {\n"
6604 " @pragma('vm:never-inline')\n"
6605 " void bar() {}\n"
6606 " return bar;\n"
6607 "}"
6608 "main() {\n"
6609 " reloadTest();\n"
6610 "}\n";
6611
6613
6614 Dart_Handle foo1_result = Dart_Invoke(lib, NewString("foo"), 0, nullptr);
6615 EXPECT_VALID(foo1_result);
6616
6617 EXPECT_VALID(Dart_Invoke(lib, NewString("main"), 0, nullptr));
6618
6619 Dart_Handle foo2_result = Dart_Invoke(lib, NewString("foo"), 0, nullptr);
6620 EXPECT_VALID(foo2_result);
6621
6622 TransitionNativeToVM transition(thread);
6623 const auto& bar1 = Function::Handle(
6625 .function());
6626 const auto& bar2 = Function::Handle(
6628 .function());
6629 EXPECT(Library::FindPragma(thread, /*only_core=*/false, bar2,
6630 Symbols::vm_never_inline()));
6631 // Should not appear on previous version of bar().
6632 EXPECT(!Library::FindPragma(thread, /*only_core=*/false, bar1,
6633 Symbols::vm_never_inline()));
6634}
6635
6636#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
6637
6638} // namespace dart
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
SkPoint pos
#define EXPECT(type, expectedAlignment, expectedSize)
#define UNREACHABLE()
Definition assert.h:248
static ObjectPtr UnwrapHandle(Dart_Handle object)
static intptr_t ClassId(Dart_Handle handle)
intptr_t Length() const
Definition object.h:10808
void SetAt(intptr_t index, const Object &value) const
Definition object.h:10858
virtual void VisitObject(ObjectPtr obj)
GrowableObjectArrayPtr direct_subclasses_unsafe() const
Definition object.h:1544
ObjectStore * object_store() const
Definition isolate.h:505
static IsolateGroup * Current()
Definition isolate.h:534
static bool FindPragma(Thread *T, bool only_core, const Object &object, const String &pragma_name, bool multiple=false, Object *options=nullptr)
Definition object.cc:4201
ClassPtr LookupClass(const String &name) const
Definition object.cc:14152
KernelProgramInfoPtr kernel_program_info() const
Definition object.h:5272
static char * SCreate(Zone *zone, const char *format,...) PRINTF_ATTRIBUTE(2
static Object & Handle()
Definition object.h:407
static ObjectPtr RawCast(ObjectPtr obj)
Definition object.h:325
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition object.cc:23777
static void AddToKernelBuffers(const uint8_t *kernel_buffer)
Definition unit_test.cc:100
static Dart_Handle TriggerReload(const uint8_t *kernel_buffer, intptr_t kernel_buffer_size)
Definition unit_test.cc:589
static Dart_Handle LoadTestScriptWithDFE(int sourcefiles_count, Dart_SourceFile sourcefiles[], Dart_NativeEntryResolver resolver=nullptr, bool finalize=true, bool incrementally=true, bool allow_compile_errors=false, const char *entry_script_uri=nullptr, const char *multiroot_filepaths=nullptr, const char *multiroot_scheme=nullptr)
Definition unit_test.cc:476
static void AddTestLib(const char *url, const char *source)
Definition unit_test.cc:188
static Dart_Handle LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri=RESOLVED_USER_TEST_URI, bool finalize=true, bool allow_compile_errors=false)
Definition unit_test.cc:422
static Dart_Handle ReloadTestScript(const char *script)
Definition unit_test.cc:599
static char * CompileTestScriptWithDFE(const char *url, const char *source, const uint8_t **kernel_buffer, intptr_t *kernel_buffer_size, bool incrementally=true, bool allow_compile_errors=false, const char *multiroot_filepaths=nullptr, const char *multiroot_scheme=nullptr)
Definition unit_test.cc:300
static const char * LateTag()
Definition unit_test.h:423
static Dart_Handle SetReloadTestScript(const char *script)
Definition unit_test.cc:525
static Dart_Handle LoadTestScriptWithErrors(const char *script, Dart_NativeEntryResolver resolver=nullptr, const char *lib_uri=RESOLVED_USER_TEST_URI, bool finalize=true)
Definition unit_test.cc:414
static Dart_Handle LoadTestLibrary(const char *lib_uri, const char *script, Dart_NativeEntryResolver resolver=nullptr)
Definition unit_test.cc:441
static Dart_Handle ReloadTestKernel(const uint8_t *kernel_buffer, intptr_t kernel_buffer_size)
Definition unit_test.cc:617
static const char * NullableTag()
Definition unit_test.h:421
static Thread * Current()
Definition thread.h:361
std::unique_ptr< char, decltype(std::free) * > CStringUniquePtr
Definition utils.h:644
struct _Dart_Handle * Dart_Handle
Definition dart_api.h:258
@ Dart_TypedData_kUint8
Definition dart_api.h:2606
Dart_LibraryTag
Definition dart_api.h:3339
@ Dart_kKernelTag
Definition dart_api.h:3342
SkBitmap source
Definition examples.cpp:28
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
GAsyncResult * result
Dart_NativeFunction function
Definition fuchsia.cc:51
DART_EXPORT bool Dart_IsLibrary(Dart_Handle object)
Dart_Handle Dart_GetLibraryDebuggable(intptr_t library_id, bool *is_debuggable)
DART_EXPORT void Dart_EnterScope()
const char *const name
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
DART_EXPORT Dart_Handle Dart_RootLibrary()
const char * SimpleInvokeStr(Dart_Handle lib, const char *method)
static bool NothingModifiedCallback(const char *url, int64_t since)
void * malloc(size_t size)
Definition allocation.cc:19
static bool MainModifiedCallback(const char *url, int64_t since)
static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag, Dart_Handle library, Dart_Handle url)
Definition unit_test.cc:378
DART_EXPORT Dart_FinalizableHandle Dart_NewFinalizableHandle(Dart_Handle object, void *peer, intptr_t external_allocation_size, Dart_HandleFinalizer callback)
DART_EXPORT char * Dart_SetFileModifiedCallback(Dart_FileModifiedCallback file_modified_callback)
Dart_Handle Dart_SetLibraryDebuggable(intptr_t library_id, bool is_debuggable)
static void TestReloadWithFieldChange(const char *prefix, const char *suffix, const char *verify, const char *from_type, const char *from_init, const char *to_type, const char *to_init)
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
DART_EXPORT Dart_Handle Dart_NewExternalTypedData(Dart_TypedData_Type type, void *data, intptr_t length)
static bool ExportModifiedCallback(const char *url, int64_t since)
Dart_Handle Dart_LibraryId(Dart_Handle library, intptr_t *library_id)
const intptr_t cid
Dart_Handle NewString(const char *str)
int64_t SimpleInvoke(Dart_Handle lib, const char *method)
DART_EXPORT Dart_Handle Dart_SetLibraryTagHandler(Dart_LibraryTagHandler handler)
DART_EXPORT void Dart_ExitScope()
DART_EXPORT Dart_Handle Dart_FinalizeAllClasses()
DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url)
DART_EXPORT bool Dart_IsInteger(Dart_Handle object)
DART_EXPORT Dart_Handle Dart_Null()
DART_EXPORT bool Dart_IsString(Dart_Handle object)
DART_EXPORT Dart_Handle Dart_SetRootLibrary(Dart_Handle library)
DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle object, const char **cstr)
static bool ImportModifiedCallback(const char *url, int64_t since)
Dart_Handle SimpleInvokeError(Dart_Handle lib, const char *method)
DART_EXPORT Dart_Handle Dart_LoadLibraryFromKernel(const uint8_t *buffer, intptr_t buffer_size)
DART_EXPORT Dart_Handle Dart_IntegerToInt64(Dart_Handle integer, int64_t *value)
#define EXPECT_ERROR(handle, substring)
Definition unit_test.h:670
#define ISOLATE_UNIT_TEST_CASE(name)
Definition unit_test.h:64
#define TEST_CASE(name)
Definition unit_test.h:85
#define EXPECT_NON_NULL(handle)
Definition unit_test.h:710
#define EXPECT_VALID(handle)
Definition unit_test.h:650
#define ARRAY_SIZE(array)
Definition globals.h:72