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