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 "include/dart_api.h"
6#include "include/dart_tools_api.h"
7#include "platform/assert.h"
8#include "vm/debugger_api_impl_test.h"
9#include "vm/globals.h"
10#include "vm/isolate.h"
11#include "vm/kernel_loader.h"
12#include "vm/lockers.h"
13#include "vm/thread_barrier.h"
14#include "vm/thread_pool.h"
15#include "vm/unit_test.h"
16
17namespace dart {
18
19#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
20
21int64_t SimpleInvoke(Dart_Handle lib, const char* method) {
22 Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
23 EXPECT_VALID(result);
24 EXPECT(Dart_IsInteger(result));
25 int64_t integer_result = 0;
26 result = Dart_IntegerToInt64(result, &integer_result);
27 EXPECT_VALID(result);
28 return integer_result;
29}
30
31const char* SimpleInvokeStr(Dart_Handle lib, const char* method) {
32 Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
33 const char* result_str = NULL;
34 EXPECT(Dart_IsString(result));
35 EXPECT_VALID(Dart_StringToCString(result, &result_str));
36 return result_str;
37}
38
39Dart_Handle SimpleInvokeError(Dart_Handle lib, const char* method) {
40 Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
41 EXPECT(Dart_IsError(result));
42 return result;
43}
44
45TEST_CASE(IsolateReload_FunctionReplacement) {
46 const char* kScript =
47 "main() {\n"
48 " return 4;\n"
49 "}\n";
50
51 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
52 EXPECT_VALID(lib);
53
54 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
55
56 const char* kReloadScript =
57 "var _unused;"
58 "main() {\n"
59 " return 10;\n"
60 "}\n";
61
62 lib = TestCase::ReloadTestScript(kReloadScript);
63 EXPECT_VALID(lib);
64 EXPECT_EQ(10, SimpleInvoke(lib, "main"));
65}
66
67TEST_CASE(IsolateReload_IncrementalCompile) {
68 const char* kScriptChars =
69 "main() {\n"
70 " return 42;\n"
71 "}\n";
72 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
73 EXPECT_VALID(lib);
74 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
75 int64_t value = 0;
76 result = Dart_IntegerToInt64(result, &value);
77 EXPECT_VALID(result);
78 EXPECT_EQ(42, value);
79
80 const char* kUpdatedScriptChars =
81 "main() {\n"
82 " return 24;\n"
83 "}\n"
84 "";
85 lib = TestCase::ReloadTestScript(kUpdatedScriptChars);
86 EXPECT_VALID(lib);
87 result = Dart_Invoke(lib, NewString("main"), 0, NULL);
88 result = Dart_IntegerToInt64(result, &value);
89 EXPECT_VALID(result);
90 EXPECT_EQ(24, value);
91}
92
93TEST_CASE(IsolateReload_KernelIncrementalCompile) {
94 // clang-format off
95 Dart_SourceFile sourcefiles[] = {
96 {
97 "file:///test-app",
98 "main() {\n"
99 " return 42;\n"
100 "}\n",
101 }};
102 // clang-format on
103
104 Dart_Handle lib = TestCase::LoadTestScriptWithDFE(
105 sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
106 NULL /* resolver */, true /* finalize */, true /* incrementally */);
107 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
108 int64_t value = 0;
109 result = Dart_IntegerToInt64(result, &value);
110 EXPECT_VALID(result);
111 EXPECT_EQ(42, value);
112
113 // clang-format off
114 Dart_SourceFile updated_sourcefiles[] = {
115 {
116 "file:///test-app",
117 "main() {\n"
118 " return 24;\n"
119 "}\n"
120 ""
121 }};
122 // clang-format on
123 {
124 const uint8_t* kernel_buffer = NULL;
125 intptr_t kernel_buffer_size = 0;
126 char* error = TestCase::CompileTestScriptWithDFE(
127 "file:///test-app",
128 sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
129 updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
130 true /* incrementally */);
131 EXPECT(error == NULL);
132 EXPECT_NOTNULL(kernel_buffer);
133
134 lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
135 EXPECT_VALID(lib);
136 }
137 result = Dart_Invoke(lib, NewString("main"), 0, NULL);
138 result = Dart_IntegerToInt64(result, &value);
139 EXPECT_VALID(result);
140 EXPECT_EQ(24, value);
141}
142
143TEST_CASE(IsolateReload_KernelIncrementalCompileAppAndLib) {
144 // clang-format off
145 Dart_SourceFile sourcefiles[] = {
146 {
147 "file:///test-app.dart",
148 "import 'test-lib.dart';\n"
149 "main() {\n"
150 " return WhatsTheMeaningOfAllThis();\n"
151 "}\n",
152 },
153 {
154 "file:///test-lib.dart",
155 "WhatsTheMeaningOfAllThis() {\n"
156 " return 42;\n"
157 "}\n",
158 }};
159 // clang-format on
160
161 Dart_Handle lib = TestCase::LoadTestScriptWithDFE(
162 sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
163 NULL /* resolver */, true /* finalize */, true /* incrementally */);
164 EXPECT_VALID(lib);
165 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
166 int64_t value = 0;
167 result = Dart_IntegerToInt64(result, &value);
168 EXPECT_VALID(result);
169 EXPECT_EQ(42, value);
170
171 // clang-format off
172 Dart_SourceFile updated_sourcefiles[] = {
173 {
174 "file:///test-lib.dart",
175 "WhatsTheMeaningOfAllThis() {\n"
176 " return 24;\n"
177 "}\n"
178 ""
179 }};
180 // clang-format on
181
182 {
183 const uint8_t* kernel_buffer = NULL;
184 intptr_t kernel_buffer_size = 0;
185 char* error = TestCase::CompileTestScriptWithDFE(
186 "file:///test-app.dart",
187 sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
188 updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
189 true /* incrementally */);
190 EXPECT(error == NULL);
191 EXPECT_NOTNULL(kernel_buffer);
192
193 lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
194 EXPECT_VALID(lib);
195 }
196 result = Dart_Invoke(lib, NewString("main"), 0, NULL);
197 result = Dart_IntegerToInt64(result, &value);
198 EXPECT_VALID(result);
199 EXPECT_EQ(24, value);
200}
201
202TEST_CASE(IsolateReload_KernelIncrementalCompileGenerics) {
203 // clang-format off
204 Dart_SourceFile sourcefiles[] = {
205 {
206 "file:///test-app.dart",
207 "import 'test-lib.dart';\n"
208 "class Account {\n"
209 " int balance() => 42;\n"
210 "}\n"
211 "class MyAccountState extends State<Account> {\n"
212 " MyAccountState(Account a): super(a) {}\n"
213 "}\n"
214 "main() {\n"
215 " return (new MyAccountState(new Account()))\n"
216 " .howAreTheThings().balance();\n"
217 "}\n",
218 },
219 {
220 "file:///test-lib.dart",
221 "class State<T> {\n"
222 " T t;"
223 " State(this.t);\n"
224 " T howAreTheThings() => t;\n"
225 "}\n",
226 }};
227 // clang-format on
228
229 Dart_Handle lib = TestCase::LoadTestScriptWithDFE(
230 sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
231 NULL /* resolver */, true /* finalize */, true /* incrementally */);
232 EXPECT_VALID(lib);
233 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
234 int64_t value = 0;
235 result = Dart_IntegerToInt64(result, &value);
236 EXPECT_VALID(result);
237 EXPECT_EQ(42, value);
238
239 // clang-format off
240 Dart_SourceFile updated_sourcefiles[] = {
241 {
242 "file:///test-app.dart",
243 "import 'test-lib.dart';\n"
244 "class Account {\n"
245 " int balance() => 24;\n"
246 "}\n"
247 "class MyAccountState extends State<Account> {\n"
248 " MyAccountState(Account a): super(a) {}\n"
249 "}\n"
250 "main() {\n"
251 " return (new MyAccountState(new Account()))\n"
252 " .howAreTheThings().balance();\n"
253 "}\n",
254 }};
255 // clang-format on
256 {
257 const uint8_t* kernel_buffer = NULL;
258 intptr_t kernel_buffer_size = 0;
259 char* error = TestCase::CompileTestScriptWithDFE(
260 "file:///test-app.dart",
261 sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
262 updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
263 true /* incrementally */);
264 EXPECT(error == NULL);
265 EXPECT_NOTNULL(kernel_buffer);
266
267 lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
268 EXPECT_VALID(lib);
269 }
270 result = Dart_Invoke(lib, NewString("main"), 0, NULL);
271 result = Dart_IntegerToInt64(result, &value);
272 EXPECT_VALID(result);
273 EXPECT_EQ(24, value);
274}
275
276TEST_CASE(IsolateReload_KernelIncrementalCompileBaseClass) {
277 const char* nullable_tag = TestCase::NullableTag();
278 // clang-format off
279 auto kSourceFile1 =
280 Utils::CStringUniquePtr(OS::SCreate(nullptr,
281 "class State<T, U> {\n"
282 " T%s t;\n"
283 " U%s 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 nullable_tag, nullable_tag),
290 std::free);
291 Dart_SourceFile sourcefiles[3] = {
292 {
293 "file:///test-app.dart",
294 "import 'test-util.dart';\n"
295 "main() {\n"
296 " var v = doWork();"
297 " return v == 42 ? 1 : v == null ? -1 : 0;\n"
298 "}\n",
299 },
300 {
301 "file:///test-lib.dart",
302 kSourceFile1.get()
303 },
304 {
305 "file:///test-util.dart",
306 "import 'test-lib.dart';\n"
307 "class MyAccountState extends State<int, String> {\n"
308 " MyAccountState(List l): super(l) {}\n"
309 " first() => t;\n"
310 "}\n"
311 "doWork() => new MyAccountState(<dynamic>[42, 'abc']).first();\n"
312 }
313 };
314 // clang-format on
315
316 Dart_Handle lib = TestCase::LoadTestScriptWithDFE(
317 sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles,
318 NULL /* resolver */, true /* finalize */, true /* incrementally */);
319 EXPECT_VALID(lib);
320 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
321 int64_t value = 0;
322 result = Dart_IntegerToInt64(result, &value);
323 EXPECT_VALID(result);
324 EXPECT_EQ(1, value);
325
326 auto kUpdatedSourceFile =
327 Utils::CStringUniquePtr(OS::SCreate(nullptr,
328 "class State<U, T> {\n"
329 " T%s t;\n"
330 " U%s u;\n"
331 " State(List l) {\n"
332 " t = l[0] is T ? l[0] : null;\n"
333 " u = l[1] is U ? l[1] : null;\n"
334 " }\n"
335 "}\n",
336 nullable_tag, nullable_tag),
337 std::free);
338 Dart_SourceFile updated_sourcefiles[1] = {{
339 "file:///test-lib.dart",
340 kUpdatedSourceFile.get(),
341 }};
342 {
343 const uint8_t* kernel_buffer = NULL;
344 intptr_t kernel_buffer_size = 0;
345 char* error = TestCase::CompileTestScriptWithDFE(
346 "file:///test-app.dart",
347 sizeof(updated_sourcefiles) / sizeof(Dart_SourceFile),
348 updated_sourcefiles, &kernel_buffer, &kernel_buffer_size,
349 true /* incrementally */);
350 EXPECT(error == NULL);
351 EXPECT_NOTNULL(kernel_buffer);
352
353 lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
354 EXPECT_VALID(lib);
355 }
356 result = Dart_Invoke(lib, NewString("main"), 0, NULL);
357 result = Dart_IntegerToInt64(result, &value);
358 EXPECT_VALID(result);
359 EXPECT_EQ(-1, value);
360}
361
362TEST_CASE(IsolateReload_BadClass) {
363 const char* kScript =
364 "class Foo {\n"
365 " final a;\n"
366 " Foo(this.a);\n"
367 "}\n"
368 "main() {\n"
369 " new Foo(5);\n"
370 " return 4;\n"
371 "}\n";
372
373 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
374 EXPECT_VALID(lib);
375 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
376
377 const char* kReloadScript =
378 "var _unused;"
379 "class Foo {\n"
380 " final a kjsdf ksjdf ;\n"
381 " Foo(this.a);\n"
382 "}\n"
383 "main() {\n"
384 " new Foo(5);\n"
385 " return 10;\n"
386 "}\n";
387
388 Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
389 EXPECT_ERROR(result, "Expected ';' after this");
390 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
391}
392
393TEST_CASE(IsolateReload_StaticValuePreserved) {
394 const char* kScript =
395 "init() => 'old value';\n"
396 "var value = init();\n"
397 "main() {\n"
398 " return 'init()=${init()},value=${value}';\n"
399 "}\n";
400
401 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
402 EXPECT_VALID(lib);
403 EXPECT_STREQ("init()=old value,value=old value",
404 SimpleInvokeStr(lib, "main"));
405
406 const char* kReloadScript =
407 "var _unused;"
408 "init() => 'new value';\n"
409 "var value = init();\n"
410 "main() {\n"
411 " return 'init()=${init()},value=${value}';\n"
412 "}\n";
413
414 lib = TestCase::ReloadTestScript(kReloadScript);
415 EXPECT_VALID(lib);
416 EXPECT_STREQ("init()=new value,value=old value",
417 SimpleInvokeStr(lib, "main"));
418}
419
420TEST_CASE(IsolateReload_SavedClosure) {
421 // Create a closure in main which only exists in the original source.
422 const char* kScript =
423 "magic() {\n"
424 " var x = 'ante';\n"
425 " return x + 'diluvian';\n"
426 "}\n"
427 "var closure;\n"
428 "main() {\n"
429 " closure = () { return magic().toString() + '!'; };\n"
430 " return closure();\n"
431 "}\n";
432
433 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
434 EXPECT_VALID(lib);
435 EXPECT_STREQ("antediluvian!", SimpleInvokeStr(lib, "main"));
436
437 // Remove the original closure from the source code. The closure is
438 // able to be recompiled because its source is preserved in a
439 // special patch class.
440 const char* kReloadScript =
441 "magic() {\n"
442 " return 'postapocalyptic';\n"
443 "}\n"
444 "var closure;\n"
445 "main() {\n"
446 " return closure();\n"
447 "}\n";
448
449 lib = TestCase::ReloadTestScript(kReloadScript);
450 EXPECT_VALID(lib);
451 EXPECT_STREQ("postapocalyptic!", SimpleInvokeStr(lib, "main"));
452}
453
454TEST_CASE(IsolateReload_TopLevelFieldAdded) {
455 const char* kScript =
456 "var value1 = 10;\n"
457 "main() {\n"
458 " return 'value1=${value1}';\n"
459 "}\n";
460
461 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
462 EXPECT_VALID(lib);
463 EXPECT_STREQ("value1=10", SimpleInvokeStr(lib, "main"));
464
465 const char* kReloadScript =
466 "var value1 = 10;\n"
467 "var value2 = 20;\n"
468 "main() {\n"
469 " return 'value1=${value1},value2=${value2}';\n"
470 "}\n";
471
472 lib = TestCase::ReloadTestScript(kReloadScript);
473 EXPECT_VALID(lib);
474 EXPECT_STREQ("value1=10,value2=20", SimpleInvokeStr(lib, "main"));
475}
476
477TEST_CASE(IsolateReload_ClassFieldAdded) {
478 const char* kScript =
479 "class Foo {\n"
480 " var x;\n"
481 "}\n"
482 "main() {\n"
483 " new Foo();\n"
484 " return 44;\n"
485 "}\n";
486
487 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
488 EXPECT_VALID(lib);
489 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
490
491 const char* kReloadScript =
492 "class Foo {\n"
493 " var x;\n"
494 " var y;\n"
495 "}\n"
496 "main() {\n"
497 " new Foo();\n"
498 " return 44;\n"
499 "}\n";
500
501 lib = TestCase::ReloadTestScript(kReloadScript);
502 EXPECT_VALID(lib);
503 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
504}
505
506TEST_CASE(IsolateReload_ClassFieldAdded2) {
507 const char* kScript =
508 "class Foo {\n"
509 " var x;\n"
510 " var y;\n"
511 "}\n"
512 "main() {\n"
513 " new Foo();\n"
514 " return 44;\n"
515 "}\n";
516
517 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
518 EXPECT_VALID(lib);
519 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
520
521 const char* kReloadScript =
522 "class Foo {\n"
523 " var x;\n"
524 " var y;\n"
525 " var z;\n"
526 "}\n"
527 "main() {\n"
528 " new Foo();\n"
529 " return 44;\n"
530 "}\n";
531
532 lib = TestCase::ReloadTestScript(kReloadScript);
533 EXPECT_VALID(lib);
534 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
535}
536
537TEST_CASE(IsolateReload_ClassFieldRemoved) {
538 const char* kScript =
539 "class Foo {\n"
540 " var x;\n"
541 " var y;\n"
542 "}\n"
543 "main() {\n"
544 " new Foo();\n"
545 " return 44;\n"
546 "}\n";
547
548 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
549 EXPECT_VALID(lib);
550 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
551
552 const char* kReloadScript =
553 "class Foo {\n"
554 " var x;\n"
555 "}\n"
556 "main() {\n"
557 " new Foo();\n"
558 " return 44;\n"
559 "}\n";
560
561 lib = TestCase::ReloadTestScript(kReloadScript);
562 EXPECT_VALID(lib);
563 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
564}
565
566TEST_CASE(IsolateReload_ClassAdded) {
567 const char* kScript =
568 "main() {\n"
569 " return 'hello';\n"
570 "}\n";
571
572 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
573 EXPECT_VALID(lib);
574 EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
575
576 const char* kReloadScript =
577 "var _unused;"
578 "class A {\n"
579 " toString() => 'hello from A';\n"
580 "}\n"
581 "main() {\n"
582 " return new A().toString();\n"
583 "}\n";
584
585 lib = TestCase::ReloadTestScript(kReloadScript);
586 EXPECT_VALID(lib);
587 EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
588}
589
590TEST_CASE(IsolateReload_ClassRemoved) {
591 const char* kScript =
592 "class A {\n"
593 " toString() => 'hello from A';\n"
594 "}\n"
595 "List<dynamic> list = <dynamic>[];"
596 "main() {\n"
597 " list.add(new A());\n"
598 " return list[0].toString();\n"
599 "}\n";
600
601 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
602 EXPECT_VALID(lib);
603 EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
604
605 const char* kReloadScript =
606 "List<dynamic> list = <dynamic>[];\n"
607 "main() {\n"
608 " return list[0].toString();\n"
609 "}\n";
610
611 lib = TestCase::ReloadTestScript(kReloadScript);
612 EXPECT_VALID(lib);
613 EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
614}
615
616TEST_CASE(IsolateReload_LibraryImportAdded) {
617 const char* kScript =
618 "main() {\n"
619 " return max(3, 4);\n"
620 "}\n";
621
622 const char* kReloadScript =
623 "import 'dart:math';\n"
624 "main() {\n"
625 " return max(3, 4);\n"
626 "}\n";
627
628 Dart_Handle lib = TestCase::LoadTestScriptWithErrors(kScript);
629 EXPECT_VALID(lib);
630 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");
631
632 lib = TestCase::ReloadTestScript(kReloadScript);
633 EXPECT_VALID(lib);
634 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
635}
636
637TEST_CASE(IsolateReload_LibraryImportRemoved) {
638 const char* kScript =
639 "import 'dart:math';\n"
640 "main() {\n"
641 " return max(3, 4);\n"
642 "}\n";
643
644 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
645 EXPECT_VALID(lib);
646 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
647
648 const char* kReloadScript =
649 "main() {\n"
650 " return max(3, 4);\n"
651 "}\n";
652
653 lib = TestCase::ReloadTestScript(kReloadScript);
654 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");
655}
656
657TEST_CASE(IsolateReload_LibraryDebuggable) {
658 const char* kScript =
659 "main() {\n"
660 " return 1;\n"
661 "}\n";
662
663 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
664 EXPECT_VALID(lib);
665
666 // The library is by default debuggable. Make it not debuggable.
667 intptr_t lib_id = -1;
668 bool debuggable = false;
669 EXPECT_VALID(Dart_LibraryId(lib, &lib_id));
670 EXPECT_VALID(Dart_GetLibraryDebuggable(lib_id, &debuggable));
671 EXPECT_EQ(true, debuggable);
672 EXPECT_VALID(Dart_SetLibraryDebuggable(lib_id, false));
673 EXPECT_VALID(Dart_GetLibraryDebuggable(lib_id, &debuggable));
674 EXPECT_EQ(false, debuggable);
675
676 EXPECT_EQ(1, SimpleInvoke(lib, "main"));
677
678 const char* kReloadScript =
679 "main() {\n"
680 " return 2;\n"
681 "}\n";
682
683 lib = TestCase::ReloadTestScript(kReloadScript);
684 EXPECT_VALID(lib);
685
686 EXPECT_EQ(2, SimpleInvoke(lib, "main"));
687
688 // Library debuggability is preserved.
689 intptr_t new_lib_id = -1;
690 EXPECT_VALID(Dart_LibraryId(lib, &new_lib_id));
691 EXPECT_VALID(Dart_GetLibraryDebuggable(new_lib_id, &debuggable));
692 EXPECT_EQ(false, debuggable);
693}
694
695TEST_CASE(IsolateReload_ImplicitConstructorChanged) {
696 // Note that we are checking that the value 20 gets cleared from the
697 // compile-time constants cache. To make this test work, "20" and
698 // "10" need to be at the same token position.
699 const char* kScript =
700 "class A {\n"
701 " int field = 20;\n"
702 "}\n"
703 "var savedA = new A();\n"
704 "main() {\n"
705 " var newA = new A();\n"
706 " return 'saved:${savedA.field} new:${newA.field}';\n"
707 "}\n";
708
709 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
710 EXPECT_VALID(lib);
711 EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
712
713 const char* kReloadScript =
714 "class A {\n"
715 " int field = 10;\n"
716 "}\n"
717 "var savedA = new A();\n"
718 "main() {\n"
719 " var newA = new A();\n"
720 " return 'saved:${savedA.field} new:${newA.field}';\n"
721 "}\n";
722
723 lib = TestCase::ReloadTestScript(kReloadScript);
724 EXPECT_VALID(lib);
725 EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
726}
727
728TEST_CASE(IsolateReload_ConstructorChanged) {
729 const char* late_tag = TestCase::LateTag();
730 // clang-format off
731 auto kScript = Utils::CStringUniquePtr(
732 OS::SCreate(nullptr,
733 "class A {\n"
734 " %s int field;\n"
735 " A() { field = 20; }\n"
736 "}\n"
737 "var savedA = A();\n"
738 "main() {\n"
739 " var newA = A();\n"
740 " return 'saved:${savedA.field} new:${newA.field}';\n"
741 "}\n",
742 late_tag),
743 std::free);
744 // clang-format on
745
746 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
747 EXPECT_VALID(lib);
748 EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
749
750 // clang-format off
751 auto kReloadScript = Utils::CStringUniquePtr(
752 OS::SCreate(nullptr,
753 "var _unused;"
754 "class A {\n"
755 " %s int field;\n"
756 " A() { field = 10; }\n"
757 "}\n"
758 "var savedA = A();\n"
759 "main() {\n"
760 " var newA = A();\n"
761 " return 'saved:${savedA.field} new:${newA.field}';\n"
762 "}\n",
763 late_tag),
764 std::free);
765 // clang-format on
766
767 lib = TestCase::ReloadTestScript(kReloadScript.get());
768 EXPECT_VALID(lib);
769 EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
770}
771
772TEST_CASE(IsolateReload_SuperClassChanged) {
773 const char* kScript =
774 "class A {\n"
775 "}\n"
776 "class B extends A {\n"
777 "}\n"
778 "var list = [ new A(), new B() ];\n"
779 "main() {\n"
780 " return (list.map((x) => '${x is A}/${x is B}')).toString();\n"
781 "}\n";
782
783 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
784 EXPECT_VALID(lib);
785 EXPECT_STREQ("(true/false, true/true)", SimpleInvokeStr(lib, "main"));
786
787 const char* kReloadScript =
788 "var _unused;"
789 "class B{\n"
790 "}\n"
791 "class A extends B {\n"
792 "}\n"
793 "var list = [ new A(), new B() ];\n"
794 "main() {\n"
795 " return (list.map((x) => '${x is A}/${x is B}')).toString();\n"
796 "}\n";
797
798 lib = TestCase::ReloadTestScript(kReloadScript);
799 EXPECT_VALID(lib);
800 EXPECT_STREQ("(true/true, false/true)", SimpleInvokeStr(lib, "main"));
801}
802
803TEST_CASE(IsolateReload_Generics) {
804 // Reload a program with generics without changing the source. We
805 // do this to produce duplication TypeArguments and make sure that
806 // the system doesn't die.
807 const char* kScript =
808 "class A {\n"
809 "}\n"
810 "class B<T extends A> {\n"
811 "}\n"
812 "main() {\n"
813 " return new B<A>().toString();\n"
814 "}\n";
815
816 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
817 EXPECT_VALID(lib);
818 EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
819
820 const char* kReloadScript =
821 "class A {\n"
822 "}\n"
823 "class B<T extends A> {\n"
824 "}\n"
825 "main() {\n"
826 " return new B<A>().toString();\n"
827 "}\n";
828
829 lib = TestCase::ReloadTestScript(kReloadScript);
830 EXPECT_VALID(lib);
831 EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
832}
833
834TEST_CASE(IsolateReload_TypeIdentity) {
835 const char* kScript =
836 "import 'file:///test:isolate_reload_helper';\n"
837 "class T { }\n"
838 "getType() => T;\n"
839 "main() {\n"
840 " var oldType = getType();\n"
841 " reloadTest();\n"
842 " var newType = getType();\n"
843 " return identical(oldType, newType).toString();\n"
844 "}\n";
845
846 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
847 EXPECT_VALID(lib);
848
849 const char* kReloadScript =
850 "import 'file:///test:isolate_reload_helper';\n"
851 "class T extends Stopwatch { }\n"
852 "getType() => T;\n"
853 "main() {\n"
854 " var oldType = getType();\n"
855 " reloadTest();\n"
856 " var newType = getType();\n"
857 " return identical(oldType, newType).toString();\n"
858 "}\n";
859
860 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
861
862 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
863}
864
865TEST_CASE(IsolateReload_TypeIdentityGeneric) {
866 const char* kScript =
867 "import 'file:///test:isolate_reload_helper';\n"
868 "class T<G> { }\n"
869 "getType() => new T<int>().runtimeType;\n"
870 "main() {\n"
871 " var oldType = getType();\n"
872 " reloadTest();\n"
873 " var newType = getType();\n"
874 " return identical(oldType, newType).toString();\n"
875 "}\n";
876
877 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
878 EXPECT_VALID(lib);
879
880 const char* kReloadScript =
881 "import 'file:///test:isolate_reload_helper';\n"
882 "class T<G> extends Stopwatch { }\n"
883 "getType() => new T<int>().runtimeType;\n"
884 "main() {\n"
885 " var oldType = getType();\n"
886 " reloadTest();\n"
887 " var newType = getType();\n"
888 " return identical(oldType, newType).toString();\n"
889 "}\n";
890
891 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
892
893 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
894}
895
896TEST_CASE(IsolateReload_TypeIdentityParameter) {
897 const char* kScript =
898 "import 'dart:mirrors';\n"
899 "import 'file:///test:isolate_reload_helper';\n"
900 "class T<G> { }\n"
901 "getTypeVar() => reflectType(T).typeVariables[0];\n"
902 "main() {\n"
903 " var oldType = getTypeVar();\n"
904 " reloadTest();\n"
905 " var newType = getTypeVar();\n"
906 " return (oldType == newType).toString();\n"
907 "}\n";
908
909 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
910 EXPECT_VALID(lib);
911
912 const char* kReloadScript =
913 "import 'dart:mirrors';\n"
914 "import 'file:///test:isolate_reload_helper';\n"
915 "class T<G> extends Stopwatch { }\n"
916 "getTypeVar() => reflectType(T).typeVariables[0];\n"
917 "main() {\n"
918 " var oldType = getTypeVar();\n"
919 " reloadTest();\n"
920 " var newType = getTypeVar();\n"
921 " return (oldType == newType).toString();\n"
922 "}\n";
923
924 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
925
926 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
927}
928
929TEST_CASE(IsolateReload_MixinChanged) {
930 const char* kScript =
931 "class Mixin1 {\n"
932 " var field = 'mixin1';\n"
933 " func() => 'mixin1';\n"
934 "}\n"
935 "class B extends Object with Mixin1 {\n"
936 "}\n"
937 "var saved = new B();\n"
938 "main() {\n"
939 " return 'saved:field=${saved.field},func=${saved.func()}';\n"
940 "}\n";
941
942 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
943 EXPECT_VALID(lib);
944 EXPECT_STREQ("saved:field=mixin1,func=mixin1", SimpleInvokeStr(lib, "main"));
945
946 const char* kReloadScript =
947 "class Mixin2 {\n"
948 " var field = 'mixin2';\n"
949 " func() => 'mixin2';\n"
950 "}\n"
951 "class B extends Object with Mixin2 {\n"
952 "}\n"
953 "var saved = new B();\n"
954 "main() {\n"
955 " var newer = new B();\n"
956 " return 'saved:field=${saved.field},func=${saved.func()} '\n"
957 " 'newer:field=${newer.field},func=${newer.func()}';\n"
958 "}\n";
959
960 lib = TestCase::ReloadTestScript(kReloadScript);
961 EXPECT_VALID(lib);
962
963 // The saved instance of B retains its old field value from mixin1,
964 // but it gets the new implementation of func from mixin2.
965 EXPECT_STREQ(
966 "saved:field=mixin1,func=mixin2 "
967 "newer:field=mixin2,func=mixin2",
968 SimpleInvokeStr(lib, "main"));
969}
970
971TEST_CASE(IsolateReload_ComplexInheritanceChange) {
972 const char* kScript =
973 "class A {\n"
974 " String name;\n"
975 " A(this.name);\n"
976 "}\n"
977 "class B extends A {\n"
978 " B(name) : super(name);\n"
979 "}\n"
980 "class C extends B {\n"
981 " C(name) : super(name);\n"
982 "}\n"
983 "var list = <dynamic>[ new A('a'), new B('b'), new C('c') ];\n"
984 "main() {\n"
985 " return (list.map((x) {\n"
986 " return '${x.name} is A(${x is A})/ B(${x is B})/ C(${x is C})';\n"
987 " })).toString();\n"
988 "}\n";
989
990 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
991 EXPECT_VALID(lib);
992 EXPECT_STREQ(
993 "(a is A(true)/ B(false)/ C(false),"
994 " b is A(true)/ B(true)/ C(false),"
995 " c is A(true)/ B(true)/ C(true))",
996 SimpleInvokeStr(lib, "main"));
997
998 const char* kReloadScript =
999 "class C {\n"
1000 " String name;\n"
1001 " C(this.name);\n"
1002 "}\n"
1003 "class X extends C {\n"
1004 " X(name) : super(name);\n"
1005 "}\n"
1006 "class A extends X {\n"
1007 " A(name) : super(name);\n"
1008 "}\n"
1009 "var list;\n"
1010 "main() {\n"
1011 " list.add(new X('x'));\n"
1012 " return (list.map((x) {\n"
1013 " return '${x.name} is A(${x is A})/ C(${x is C})/ X(${x is X})';\n"
1014 " })).toString();\n"
1015 "}\n";
1016
1017 lib = TestCase::ReloadTestScript(kReloadScript);
1018 EXPECT_VALID(lib);
1019 EXPECT_STREQ(
1020 "(a is A(true)/ C(true)/ X(true),"
1021 " b is A(true)/ C(true)/ X(true)," // still extends A...
1022 " c is A(false)/ C(true)/ X(false),"
1023 " x is A(false)/ C(true)/ X(true))",
1024 SimpleInvokeStr(lib, "main"));
1025
1026 // Revive the class B and make sure all allocated instances take
1027 // their place in the inheritance hierarchy.
1028 const char* kReloadScript2 =
1029 "class X {\n"
1030 " String name;\n"
1031 " X(this.name);\n"
1032 "}\n"
1033 "class A extends X{\n"
1034 " A(name) : super(name);\n"
1035 "}\n"
1036 "class B extends X {\n"
1037 " B(name) : super(name);\n"
1038 "}\n"
1039 "class C extends A {\n"
1040 " C(name) : super(name);\n"
1041 "}\n"
1042 "var list;\n"
1043 "main() {\n"
1044 " return (list.map((x) {\n"
1045 " return '${x.name} is '\n"
1046 " 'A(${x is A})/ B(${x is B})/ C(${x is C})/ X(${x is X})';\n"
1047 " })).toString();\n"
1048 "}\n";
1049
1050 lib = TestCase::ReloadTestScript(kReloadScript2);
1051 EXPECT_VALID(lib);
1052 EXPECT_STREQ(
1053 "(a is A(true)/ B(false)/ C(false)/ X(true),"
1054 " b is A(false)/ B(true)/ C(false)/ X(true),"
1055 " c is A(true)/ B(false)/ C(true)/ X(true),"
1056 " x is A(false)/ B(false)/ C(false)/ X(true))",
1057 SimpleInvokeStr(lib, "main"));
1058}
1059
1060TEST_CASE(IsolateReload_LiveStack) {
1061 const char* kScript =
1062 "import 'file:///test:isolate_reload_helper';\n"
1063 "helper() => 7;\n"
1064 "alpha() { var x = helper(); reloadTest(); return x + helper(); }\n"
1065 "foo() => alpha();\n"
1066 "bar() => foo();\n"
1067 "main() {\n"
1068 " return bar();\n"
1069 "}\n";
1070
1071 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1072 EXPECT_VALID(lib);
1073
1074 const char* kReloadScript =
1075 "import 'file:///test:isolate_reload_helper';\n"
1076 "helper() => 100;\n"
1077 "alpha() => 5 + helper();\n"
1078 "foo() => alpha();\n"
1079 "bar() => foo();\n"
1080 "main() {\n"
1081 " return bar();\n"
1082 "}\n";
1083
1084 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1085
1086 EXPECT_EQ(107, SimpleInvoke(lib, "main"));
1087
1088 lib = Dart_RootLibrary();
1089 EXPECT_NON_NULL(lib);
1090 EXPECT_EQ(105, SimpleInvoke(lib, "main"));
1091}
1092
1093TEST_CASE(IsolateReload_LibraryLookup) {
1094 const char* kImportScript = "importedFunc() => 'a';\n";
1095 TestCase::AddTestLib("test:lib1", kImportScript);
1096
1097 const char* kScript =
1098 "main() {\n"
1099 " return importedFunc();\n"
1100 "}\n";
1101 Dart_Handle result;
1102 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1103 EXPECT_VALID(lib);
1104 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
1105
1106 // Fail to find 'test:lib1' in the isolate.
1107 result = Dart_LookupLibrary(NewString("test:lib1"));
1108 EXPECT(Dart_IsError(result));
1109
1110 const char* kReloadScript =
1111 "import 'test:lib1';\n"
1112 "main() {\n"
1113 " return importedFunc();\n"
1114 "}\n";
1115
1116 // Reload and add 'test:lib1' to isolate.
1117 lib = TestCase::ReloadTestScript(kReloadScript);
1118 EXPECT_VALID(lib);
1119 EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
1120
1121 // Find 'test:lib1' in the isolate.
1122 result = Dart_LookupLibrary(NewString("test:lib1"));
1123 EXPECT(Dart_IsLibrary(result));
1124
1125 // Reload and remove 'dart:math' from isolate.
1126 lib = TestCase::ReloadTestScript(kScript);
1127 EXPECT_VALID(lib);
1128
1129 // Fail to find 'test:lib1' in the isolate.
1130 result = Dart_LookupLibrary(NewString("test:lib1"));
1131 EXPECT(Dart_IsError(result));
1132}
1133
1134TEST_CASE(IsolateReload_LibraryHide) {
1135 const char* kImportScript = "importedFunc() => 'a';\n";
1136 TestCase::AddTestLib("test:lib1", kImportScript);
1137
1138 // Import 'test:lib1' with importedFunc hidden. Will result in an
1139 // error.
1140 const char* kScript =
1141 "import 'test:lib1' hide importedFunc;\n"
1142 "main() {\n"
1143 " return importedFunc();\n"
1144 "}\n";
1145
1146 // Dart_Handle result;
1147
1148 Dart_Handle lib = TestCase::LoadTestScriptWithErrors(kScript);
1149 EXPECT_VALID(lib);
1150 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
1151
1152 // Import 'test:lib1'.
1153 const char* kReloadScript =
1154 "import 'test:lib1';\n"
1155 "main() {\n"
1156 " return importedFunc();\n"
1157 "}\n";
1158
1159 lib = TestCase::ReloadTestScript(kReloadScript);
1160 EXPECT_VALID(lib);
1161 EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
1162}
1163
1164TEST_CASE(IsolateReload_LibraryShow) {
1165 const char* kImportScript =
1166 "importedFunc() => 'a';\n"
1167 "importedIntFunc() => 4;\n";
1168 TestCase::AddTestLib("test:lib1", kImportScript);
1169
1170 // Import 'test:lib1' with importedIntFunc visible. Will result in
1171 // an error when 'main' is invoked.
1172 const char* kScript =
1173 "import 'test:lib1' show importedIntFunc;\n"
1174 "main() {\n"
1175 " return importedFunc();\n"
1176 "}\n"
1177 "mainInt() {\n"
1178 " return importedIntFunc();\n"
1179 "}\n";
1180
1181 Dart_Handle lib = TestCase::LoadTestScriptWithErrors(kScript);
1182 EXPECT_VALID(lib);
1183
1184 // Works.
1185 EXPECT_EQ(4, SimpleInvoke(lib, "mainInt"));
1186 // Results in an error.
1187 EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
1188
1189 // Import 'test:lib1' with importedFunc visible. Will result in
1190 // an error when 'mainInt' is invoked.
1191 const char* kReloadScript =
1192 "import 'test:lib1' show importedFunc;\n"
1193 "main() {\n"
1194 " return importedFunc();\n"
1195 "}\n"
1196 "mainInt() {\n"
1197 " return importedIntFunc();\n"
1198 "}\n";
1199
1200 lib = TestCase::ReloadTestScript(kReloadScript);
1201 EXPECT_ERROR(lib, "importedIntFunc");
1202}
1203
1204// Verifies that we clear the ICs for the functions live on the stack in a way
1205// that is compatible with the fast path smi stubs.
1206TEST_CASE(IsolateReload_SmiFastPathStubs) {
1207 const char* kImportScript = "importedIntFunc() => 4;\n";
1208 TestCase::AddTestLib("test:lib1", kImportScript);
1209
1210 const char* kScript =
1211 "import 'file:///test:isolate_reload_helper';\n"
1212 "import 'test:lib1' show importedIntFunc;\n"
1213 "main() {\n"
1214 " var x = importedIntFunc();\n"
1215 " var y = importedIntFunc();\n"
1216 " reloadTest();\n"
1217 " return x + y;\n"
1218 "}\n";
1219
1220 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1221 EXPECT_VALID(lib);
1222
1223 // Identity reload.
1224 EXPECT_VALID(TestCase::SetReloadTestScript(kScript));
1225
1226 EXPECT_EQ(8, SimpleInvoke(lib, "main"));
1227}
1228
1229// Verifies that we assign the correct patch classes for imported
1230// mixins when we reload.
1231TEST_CASE(IsolateReload_ImportedMixinFunction) {
1232 const char* kImportScript =
1233 "class ImportedMixin {\n"
1234 " mixinFunc() => 'mixin';\n"
1235 "}\n";
1236 TestCase::AddTestLib("test:lib1", kImportScript);
1237
1238 const char* kScript =
1239 "import 'test:lib1' show ImportedMixin;\n"
1240 "class A extends Object with ImportedMixin {\n"
1241 "}"
1242 "var func = new A().mixinFunc;\n"
1243 "main() {\n"
1244 " return func();\n"
1245 "}\n";
1246
1247 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1248 EXPECT_VALID(lib);
1249
1250 EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
1251
1252 const char* kReloadScript =
1253 "import 'test:lib1' show ImportedMixin;\n"
1254 "class A extends Object with ImportedMixin {\n"
1255 "}"
1256 "var func;\n"
1257 "main() {\n"
1258 " return func();\n"
1259 "}\n";
1260
1261 lib = TestCase::ReloadTestScript(kReloadScript);
1262 EXPECT_VALID(lib);
1263 EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
1264}
1265
1266TEST_CASE(IsolateReload_TopLevelParseError) {
1267 const char* kScript =
1268 "main() {\n"
1269 " return 4;\n"
1270 "}\n";
1271
1272 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1273 EXPECT_VALID(lib);
1274 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
1275
1276 const char* kReloadScript =
1277 "kjsadkfjaksldfjklsadf;\n"
1278 "main() {\n"
1279 " return 4;\n"
1280 "}\n";
1281
1282 lib = TestCase::ReloadTestScript(kReloadScript);
1283 EXPECT_ERROR(lib,
1284 "Variables must be declared using the keywords"
1285 " 'const', 'final', 'var' or a type name.");
1286}
1287
1288TEST_CASE(IsolateReload_PendingUnqualifiedCall_StaticToInstance) {
1289 const char* kScript =
1290 "import 'file:///test:isolate_reload_helper';\n"
1291 "class C {\n"
1292 " static foo() => 'static';\n"
1293 " test() {\n"
1294 " reloadTest();\n"
1295 " return foo();\n"
1296 " }\n"
1297 "}\n"
1298 "main() {\n"
1299 " return new C().test();\n"
1300 "}\n";
1301
1302 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1303 EXPECT_VALID(lib);
1304
1305 const char* kReloadScript =
1306 "import 'file:///test:isolate_reload_helper';\n"
1307 "class C {\n"
1308 " foo() => 'instance';\n"
1309 " test() {\n"
1310 " reloadTest();\n"
1311 " return foo();\n"
1312 " }\n"
1313 "}\n"
1314 "main() {\n"
1315 " return new C().test();\n"
1316 "}\n";
1317
1318 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1319
1320 const char* expected = "instance";
1321 const char* result = SimpleInvokeStr(lib, "main");
1322 EXPECT_STREQ(expected, result);
1323
1324 // Bail out if we've already failed so we don't crash in the tag handler.
1325 if ((result == NULL) || (strcmp(expected, result) != 0)) {
1326 return;
1327 }
1328
1329 lib = Dart_RootLibrary();
1330 EXPECT_NON_NULL(lib);
1331 EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
1332}
1333
1334TEST_CASE(IsolateReload_PendingUnqualifiedCall_InstanceToStatic) {
1335 const char* kScript =
1336 "import 'file:///test:isolate_reload_helper';\n"
1337 "class C {\n"
1338 " foo() => 'instance';\n"
1339 " test() {\n"
1340 " reloadTest();\n"
1341 " return foo();\n"
1342 " }\n"
1343 "}\n"
1344 "main() {\n"
1345 " return new C().test();\n"
1346 "}\n";
1347
1348 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1349 EXPECT_VALID(lib);
1350
1351 const char* kReloadScript =
1352 "import 'file:///test:isolate_reload_helper';\n"
1353 "class C {\n"
1354 " static foo() => 'static';\n"
1355 " test() {\n"
1356 " reloadTest();\n"
1357 " return foo();\n"
1358 " }\n"
1359 "}\n"
1360 "main() {\n"
1361 " return new C().test();\n"
1362 "}\n";
1363
1364 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1365
1366 const char* expected = "static";
1367 const char* result = SimpleInvokeStr(lib, "main");
1368 EXPECT_NOTNULL(result);
1369
1370 // Bail out if we've already failed so we don't crash in StringEquals.
1371 if (result == NULL) {
1372 return;
1373 }
1374 EXPECT_STREQ(expected, result);
1375
1376 // Bail out if we've already failed so we don't crash in the tag handler.
1377 if (strcmp(expected, result) != 0) {
1378 return;
1379 }
1380
1381 lib = Dart_RootLibrary();
1382 EXPECT_NON_NULL(lib);
1383 EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
1384}
1385
1386TEST_CASE(IsolateReload_PendingConstructorCall_AbstractToConcrete) {
1387 const char* kScript =
1388 "import 'file:///test:isolate_reload_helper';\n"
1389 "abstract class Foo {}\n"
1390 "class C {\n"
1391 " test() {\n"
1392 " reloadTest();\n"
1393 " return new Foo();\n"
1394 " }\n"
1395 "}\n"
1396 "main() {\n"
1397 " try {\n"
1398 " new C().test();\n"
1399 " return 'okay';\n"
1400 " } catch (e) {\n"
1401 " return 'exception';\n"
1402 " }\n"
1403 "}\n";
1404
1405 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1406 EXPECT_VALID(lib);
1407
1408 const char* kReloadScript =
1409 "import 'file:///test:isolate_reload_helper';\n"
1410 "class Foo {}\n"
1411 "class C {\n"
1412 " test() {\n"
1413 " reloadTest();\n"
1414 " return new Foo();\n"
1415 " }\n"
1416 "}\n"
1417 "main() {\n"
1418 " try {\n"
1419 " new C().test();\n"
1420 " return 'okay';\n"
1421 " } catch (e) {\n"
1422 " return 'exception';\n"
1423 " }\n"
1424 "}\n";
1425
1426 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1427
1428 const char* expected = "okay";
1429 const char* result = SimpleInvokeStr(lib, "main");
1430 EXPECT_STREQ(expected, result);
1431
1432 // Bail out if we've already failed so we don't crash in the tag handler.
1433 if ((result == NULL) || (strcmp(expected, result) != 0)) {
1434 return;
1435 }
1436
1437 lib = Dart_RootLibrary();
1438 EXPECT_NON_NULL(lib);
1439 EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
1440}
1441
1442TEST_CASE(IsolateReload_PendingConstructorCall_ConcreteToAbstract) {
1443 const char* kScript =
1444 "import 'file:///test:isolate_reload_helper';\n"
1445 "class Foo {}\n"
1446 "class C {\n"
1447 " test() {\n"
1448 " reloadTest();\n"
1449 " return new Foo();\n"
1450 " }\n"
1451 "}\n"
1452 "main() {\n"
1453 " try {\n"
1454 " new C().test();\n"
1455 " return 'okay';\n"
1456 " } catch (e) {\n"
1457 " return 'exception';\n"
1458 " }\n"
1459 "}\n";
1460
1461 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1462 EXPECT_VALID(lib);
1463
1464 const char* kReloadScript =
1465 "import 'file:///test:isolate_reload_helper';\n"
1466 "abstract class Foo {}\n"
1467 "class C {\n"
1468 " test() {\n"
1469 " reloadTest();\n"
1470 " return new Foo();\n"
1471 " }\n"
1472 "}\n"
1473 "main() {\n"
1474 " try {\n"
1475 " new C().test();\n"
1476 " return 'okay';\n"
1477 " } catch (e) {\n"
1478 " return 'exception';\n"
1479 " }\n"
1480 "}\n";
1481
1482 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1483
1484 const char* expected = "exception";
1485 const char* result = SimpleInvokeStr(lib, "main");
1486 EXPECT_STREQ(expected, result);
1487
1488 // Bail out if we've already failed so we don't crash in the tag handler.
1489 if ((result == NULL) || (strcmp(expected, result) != 0)) {
1490 return;
1491 }
1492
1493 lib = Dart_RootLibrary();
1494 EXPECT_NON_NULL(lib);
1495 EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
1496}
1497
1498TEST_CASE(IsolateReload_PendingStaticCall_DefinedToNSM) {
1499 const char* kScript =
1500 "import 'file:///test:isolate_reload_helper';\n"
1501 "class C {\n"
1502 " static foo() => 'static';\n"
1503 " test() {\n"
1504 " reloadTest();\n"
1505 " return C.foo();\n"
1506 " }\n"
1507 "}\n"
1508 "main() {\n"
1509 " try {\n"
1510 " return new C().test();\n"
1511 " } catch (e) {\n"
1512 " return 'exception';\n"
1513 " }\n"
1514 "}\n";
1515
1516 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1517 EXPECT_VALID(lib);
1518
1519 const char* kReloadScript =
1520 "import 'file:///test:isolate_reload_helper';\n"
1521 "class C {\n"
1522 " test() {\n"
1523 " reloadTest();\n"
1524 " return C.foo();\n"
1525 " }\n"
1526 "}\n"
1527 "main() {\n"
1528 " try {\n"
1529 " return new C().test();\n"
1530 " } catch (e) {\n"
1531 " return 'exception';\n"
1532 " }\n"
1533 "}\n";
1534
1535 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1536
1537 const char* expected = "exception";
1538 const char* result = SimpleInvokeStr(lib, "main");
1539 EXPECT_NOTNULL(result);
1540
1541 // Bail out if we've already failed so we don't crash in StringEquals.
1542 if (result == NULL) {
1543 return;
1544 }
1545 EXPECT_STREQ(expected, result);
1546
1547 // Bail out if we've already failed so we don't crash in the tag handler.
1548 if (strcmp(expected, result) != 0) {
1549 return;
1550 }
1551
1552 EXPECT_STREQ(expected, result);
1553 lib = Dart_RootLibrary();
1554 EXPECT_NON_NULL(lib);
1555 EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
1556}
1557
1558TEST_CASE(IsolateReload_PendingStaticCall_NSMToDefined) {
1559 const char* kScript =
1560 "import 'file:///test:isolate_reload_helper';\n"
1561 "class C {\n"
1562 " test() {\n"
1563 " reloadTest();\n"
1564 " return C.foo();\n"
1565 " }\n"
1566 "}\n"
1567 "main() {\n"
1568 " try {\n"
1569 " return new C().test();\n"
1570 " } catch (e) {\n"
1571 " return 'exception';\n"
1572 " }\n"
1573 "}\n";
1574
1575 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1576 EXPECT_VALID(lib);
1577
1578 const char* kReloadScript =
1579 "import 'file:///test:isolate_reload_helper';\n"
1580 "class C {\n"
1581 " static foo() => 'static';\n"
1582 " test() {\n"
1583 " reloadTest();\n"
1584 " return C.foo();\n"
1585 " }\n"
1586 "}\n"
1587 "main() {\n"
1588 " try {\n"
1589 " return new C().test();\n"
1590 " } catch (e) {\n"
1591 " return 'exception';\n"
1592 " }\n"
1593 "}\n";
1594
1595 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1596
1597 const char* expected = "static";
1598 const char* result = SimpleInvokeStr(lib, "main");
1599 EXPECT_STREQ(expected, result);
1600
1601 // Bail out if we've already failed so we don't crash in the tag handler.
1602 if ((result == NULL) || (strcmp(expected, result) != 0)) {
1603 return;
1604 }
1605
1606 lib = Dart_RootLibrary();
1607 EXPECT_NON_NULL(lib);
1608 EXPECT_STREQ(expected, SimpleInvokeStr(lib, "main"));
1609}
1610
1611TEST_CASE(IsolateReload_PendingSuperCall) {
1612 const char* kScript =
1613 "import 'file:///test:isolate_reload_helper';\n"
1614 "class S {\n"
1615 " foo() => 1;\n"
1616 "}\n"
1617 "class C extends S {\n"
1618 " foo() => 100;\n"
1619 " test() {\n"
1620 " var n = super.foo();\n"
1621 " reloadTest();\n"
1622 " return n + super.foo();\n"
1623 " }\n"
1624 "}\n"
1625 "main() {\n"
1626 " return new C().test();\n"
1627 "}\n";
1628
1629 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1630 EXPECT_VALID(lib);
1631
1632 const char* kReloadScript =
1633 "import 'file:///test:isolate_reload_helper';\n"
1634 "class S {\n"
1635 " foo() => 10;\n"
1636 "}\n"
1637 "class C extends S {\n"
1638 " foo() => 100;\n"
1639 " test() {\n"
1640 " var n = super.foo();\n"
1641 " reloadTest();\n"
1642 " return n + super.foo();\n"
1643 " }\n"
1644 "}\n"
1645 "main() {\n"
1646 " return new C().test();\n"
1647 "}\n";
1648
1649 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1650
1651 EXPECT_EQ(11, SimpleInvoke(lib, "main"));
1652}
1653
1654TEST_CASE(IsolateReload_TearOff_Instance_Equality) {
1655 const char* kScript =
1656 "import 'file:///test:isolate_reload_helper';\n"
1657 "class C {\n"
1658 " foo() => 'old';\n"
1659 "}\n"
1660 "main() {\n"
1661 " var c = new C();\n"
1662 " var f1 = c.foo;\n"
1663 " reloadTest();\n"
1664 " var f2 = c.foo;\n"
1665 " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
1666 "}\n";
1667
1668 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1669 EXPECT_VALID(lib);
1670
1671 const char* kReloadScript =
1672 "import 'file:///test:isolate_reload_helper';\n"
1673 "class C {\n"
1674 " foo() => 'new';\n"
1675 "}\n"
1676 "main() {\n"
1677 " var c = new C();\n"
1678 " var f1 = c.foo;\n"
1679 " reloadTest();\n"
1680 " var f2 = c.foo;\n"
1681 " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
1682 "}\n";
1683
1684 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1685
1686 EXPECT_STREQ("new new true false", SimpleInvokeStr(lib, "main"));
1687
1688 lib = Dart_RootLibrary();
1689 EXPECT_NON_NULL(lib);
1690}
1691
1692TEST_CASE(IsolateReload_TearOff_Parameter_Count_Mismatch) {
1693 const char* kScript =
1694 "import 'file:///test:isolate_reload_helper';\n"
1695 "class C {\n"
1696 " static foo() => 'old';\n"
1697 "}\n"
1698 "main() {\n"
1699 " var f1 = C.foo;\n"
1700 " reloadTest();\n"
1701 " return f1();\n"
1702 "}\n";
1703
1704 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1705 EXPECT_VALID(lib);
1706
1707 const char* kReloadScript =
1708 "import 'file:///test:isolate_reload_helper';\n"
1709 "class C {\n"
1710 " static foo(i) => 'new:$i';\n"
1711 "}\n"
1712 "main() {\n"
1713 " var f1 = C.foo;\n"
1714 " reloadTest();\n"
1715 " return f1();\n"
1716 "}\n";
1717
1718 TestCase::SetReloadTestScript(kReloadScript);
1719 Dart_Handle error_handle = SimpleInvokeError(lib, "main");
1720
1721 const char* error;
1722 error =
1723 "/test-lib:8:12: Error: Too few positional"
1724 " arguments: 1 required, 0 given.\n"
1725 " return f1();";
1726 EXPECT_ERROR(error_handle, error);
1727}
1728
1729TEST_CASE(IsolateReload_TearOff_Remove) {
1730 const char* kScript =
1731 "import 'file:///test:isolate_reload_helper';\n"
1732 "class C {\n"
1733 " static foo({String bar: 'bar'}) => 'old';\n"
1734 "}\n"
1735 "main() {\n"
1736 " var f1 = C.foo;\n"
1737 " reloadTest();\n"
1738 " try {\n"
1739 " return f1();\n"
1740 " } catch(e) { return '$e'; }\n"
1741 "}\n";
1742
1743 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1744 EXPECT_VALID(lib);
1745
1746 const char* kReloadScript =
1747 "import 'file:///test:isolate_reload_helper';\n"
1748 "class C {\n"
1749 "}\n"
1750 "main() {\n"
1751 " var f1;\n"
1752 " reloadTest();\n"
1753 " try {\n"
1754 " return f1();\n"
1755 " } catch(e) { return '$e'; }\n"
1756 "}\n";
1757
1758 TestCase::SetReloadTestScript(kReloadScript);
1759
1760 EXPECT_SUBSTRING(
1761 "NoSuchMethodError: No static method 'foo' declared in class 'C'.",
1762 SimpleInvokeStr(lib, "main"));
1763
1764 lib = Dart_RootLibrary();
1765 EXPECT_NON_NULL(lib);
1766}
1767
1768TEST_CASE(IsolateReload_TearOff_Class_Identity) {
1769 const char* kScript =
1770 "import 'file:///test:isolate_reload_helper';\n"
1771 "class C {\n"
1772 " static foo() => 'old';\n"
1773 "}\n"
1774 "getFoo() => C.foo;\n"
1775 "main() {\n"
1776 " var f1 = getFoo();\n"
1777 " reloadTest();\n"
1778 " var f2 = getFoo();\n"
1779 " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
1780 "}\n";
1781
1782 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1783 EXPECT_VALID(lib);
1784
1785 const char* kReloadScript =
1786 "import 'file:///test:isolate_reload_helper';\n"
1787 "class C {\n"
1788 " static foo() => 'new';\n"
1789 "}\n"
1790 "getFoo() => C.foo;\n"
1791 "main() {\n"
1792 " var f1 = getFoo();\n"
1793 " reloadTest();\n"
1794 " var f2 = getFoo();\n"
1795 " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
1796 "}\n";
1797
1798 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1799
1800 EXPECT_STREQ("new new true true", SimpleInvokeStr(lib, "main"));
1801
1802 lib = Dart_RootLibrary();
1803 EXPECT_NON_NULL(lib);
1804}
1805
1806TEST_CASE(IsolateReload_TearOff_Library_Identity) {
1807 const char* kScript =
1808 "import 'file:///test:isolate_reload_helper';\n"
1809 "foo() => 'old';\n"
1810 "getFoo() => foo;\n"
1811 "main() {\n"
1812 " var f1 = getFoo();\n"
1813 " reloadTest();\n"
1814 " var f2 = getFoo();\n"
1815 " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
1816 "}\n";
1817
1818 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1819 EXPECT_VALID(lib);
1820
1821 const char* kReloadScript =
1822 "import 'file:///test:isolate_reload_helper';\n"
1823 "foo() => 'new';\n"
1824 "getFoo() => foo;\n"
1825 "main() {\n"
1826 " var f1 = getFoo();\n"
1827 " reloadTest();\n"
1828 " var f2 = getFoo();\n"
1829 " return '${f1()} ${f2()} ${f1 == f2} ${identical(f1, f2)}';\n"
1830 "}\n";
1831
1832 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1833
1834 EXPECT_STREQ("new new true true", SimpleInvokeStr(lib, "main"));
1835
1836 lib = Dart_RootLibrary();
1837 EXPECT_NON_NULL(lib);
1838}
1839
1840TEST_CASE(IsolateReload_TearOff_List_Set) {
1841 const char* kScript =
1842 "import 'file:///test:isolate_reload_helper';\n"
1843 "class C {\n"
1844 " foo() => 'old';\n"
1845 "}\n"
1846 "List list = List<dynamic>.filled(2, null);\n"
1847 "Set set = Set();\n"
1848 "main() {\n"
1849 " var c = C();\n"
1850 " list[0] = c.foo;\n"
1851 " list[1] = c.foo;\n"
1852 " set.add(c.foo);\n"
1853 " set.add(c.foo);\n"
1854 " int countBefore = set.length;\n"
1855 " reloadTest();\n"
1856 " list[1] = c.foo;\n"
1857 " set.add(c.foo);\n"
1858 " set.add(c.foo);\n"
1859 " int countAfter = set.length;\n"
1860 " return '${list[0]()} ${list[1]()} ${list[0] == list[1]} '\n"
1861 " '${countBefore == 1} ${countAfter == 1} ${(set.first)()} '\n"
1862 " '${set.first == c.foo} ${set.first == c.foo} '\n"
1863 " '${set.remove(c.foo)}';\n"
1864 "}\n";
1865
1866 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1867 EXPECT_VALID(lib);
1868
1869 const char* kReloadScript =
1870 "import 'file:///test:isolate_reload_helper';\n"
1871 "class C {\n"
1872 " foo() => 'new';\n"
1873 "}\n"
1874 "List list = List<dynamic>.filled(2, null);\n"
1875 "Set set = Set();\n"
1876 "main() {\n"
1877 " var c = C();\n"
1878 " list[0] = c.foo;\n"
1879 " list[1] = c.foo;\n"
1880 " set.add(c.foo);\n"
1881 " set.add(c.foo);\n"
1882 " int countBefore = set.length;\n"
1883 " reloadTest();\n"
1884 " list[1] = c.foo;\n"
1885 " set.add(c.foo);\n"
1886 " set.add(c.foo);\n"
1887 " int countAfter = set.length;\n"
1888 " return '${list[0]()} ${list[1]()} ${list[0] == list[1]} '\n"
1889 " '${countBefore == 1} ${countAfter == 1} ${(set.first)()} '\n"
1890 " '${set.first == c.foo} ${set.first == c.foo} '\n"
1891 " '${set.remove(c.foo)}';\n"
1892 "}\n";
1893
1894 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1895
1896 EXPECT_STREQ("new new true true true new true true true",
1897 SimpleInvokeStr(lib, "main"));
1898
1899 lib = Dart_RootLibrary();
1900 EXPECT_NON_NULL(lib);
1901}
1902
1903TEST_CASE(IsolateReload_TearOff_AddArguments) {
1904 const char* kScript =
1905 "import 'file:///test:isolate_reload_helper';\n"
1906 "class C {\n"
1907 " foo(x) => x;\n"
1908 "}\n"
1909 "invoke(f, a) {\n"
1910 " try {\n"
1911 " return f(a);\n"
1912 " } catch (e) {\n"
1913 " return e.toString().split('\\n').first;\n"
1914 " }\n"
1915 "}\n"
1916 "main() {\n"
1917 " var c = new C();\n"
1918 " var f = c.foo;\n"
1919 " var r1 = invoke(f, 1);\n"
1920 " reloadTest();\n"
1921 " var r2 = invoke(f, 1);\n"
1922 " return '$r1 $r2';\n"
1923 "}\n";
1924
1925 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1926 EXPECT_VALID(lib);
1927
1928 const char* kReloadScript =
1929 "import 'file:///test:isolate_reload_helper';\n"
1930 "class C {\n"
1931 " foo(x, y, z) => x + y + z;\n"
1932 "}\n"
1933 "invoke(f, a) {\n"
1934 " try {\n"
1935 " return f(a);\n"
1936 " } catch (e) {\n"
1937 " return e.toString().split('\\n').first;\n"
1938 " }\n"
1939 "}\n"
1940 "main() {\n"
1941 " var c = new C();\n"
1942 " var f = c.foo;\n"
1943 " var r1 = invoke(f, 1);\n"
1944 " reloadTest();\n"
1945 " var r2 = invoke(f, 1);\n"
1946 " return '$r1 $r2';\n"
1947 "}\n";
1948
1949 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
1950
1951 EXPECT_STREQ(
1952 "1 NoSuchMethodError: Class 'C' has no instance method "
1953 "'foo' with matching arguments.",
1954 SimpleInvokeStr(lib, "main"));
1955
1956 lib = Dart_RootLibrary();
1957 EXPECT_NON_NULL(lib);
1958}
1959
1960TEST_CASE(IsolateReload_TearOff_AddArguments2) {
1961 const char* kScript =
1962 "import 'file:///test:isolate_reload_helper';\n"
1963 "class C {\n"
1964 " static foo(x) => x;\n"
1965 "}\n"
1966 "invoke(f, a) {\n"
1967 " try {\n"
1968 " return f(a);\n"
1969 " } catch (e) {\n"
1970 " return e.toString().split('\\n').first;\n"
1971 " }\n"
1972 "}\n"
1973 "main() {\n"
1974 " var f = C.foo;\n"
1975 " var r1 = invoke(f, 1);\n"
1976 " reloadTest();\n"
1977 " var r2 = invoke(f, 1);\n"
1978 " return '$r1 $r2';\n"
1979 "}\n";
1980
1981 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
1982 EXPECT_VALID(lib);
1983
1984 const char* kReloadScript =
1985 "import 'file:///test:isolate_reload_helper';\n"
1986 "class C {\n"
1987 " static foo(x, y, z) => x + y + z;\n"
1988 "}\n"
1989 "invoke(f, a) {\n"
1990 " try {\n"
1991 " return f(a);\n"
1992 " } catch (e) {\n"
1993 " return e.toString().split('\\n').first;\n"
1994 " }\n"
1995 "}\n"
1996 "main() {\n"
1997 " var f = C.foo;\n"
1998 " var r1 = invoke(f, 1);\n"
1999 " reloadTest();\n"
2000 " var r2 = invoke(f, 1);\n"
2001 " return '$r1 $r2';\n"
2002 "}\n";
2003
2004 EXPECT_VALID(TestCase::SetReloadTestScript(kReloadScript));
2005
2006 EXPECT_STREQ(
2007 "1 NoSuchMethodError: Closure call with mismatched arguments: "
2008 "function 'C.foo'",
2009 SimpleInvokeStr(lib, "main"));
2010
2011 lib = Dart_RootLibrary();
2012 EXPECT_NON_NULL(lib);
2013}
2014
2015TEST_CASE(IsolateReload_EnumEquality) {
2016 const char* kScript =
2017 "enum Fruit {\n"
2018 " Apple,\n"
2019 " Banana,\n"
2020 "}\n"
2021 "var x;\n"
2022 "main() {\n"
2023 " x = Fruit.Banana;\n"
2024 " return Fruit.Apple.toString();\n"
2025 "}\n";
2026
2027 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2028 EXPECT_VALID(lib);
2029
2030 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2031
2032 const char* kReloadScript =
2033 "enum Fruit {\n"
2034 " Apple,\n"
2035 " Banana,\n"
2036 "}\n"
2037 "var x;\n"
2038 "main() {\n"
2039 " if (x == Fruit.Banana) {\n"
2040 " return 'yes';\n"
2041 " } else {\n"
2042 " return 'no';\n"
2043 " }\n"
2044 "}\n";
2045
2046 lib = TestCase::ReloadTestScript(kReloadScript);
2047 EXPECT_VALID(lib);
2048 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
2049}
2050
2051TEST_CASE(IsolateReload_EnumIdentical) {
2052 const char* kScript =
2053 "enum Fruit {\n"
2054 " Apple,\n"
2055 " Banana,\n"
2056 "}\n"
2057 "var x;\n"
2058 "main() {\n"
2059 " x = Fruit.Banana;\n"
2060 " return Fruit.Apple.toString();\n"
2061 "}\n";
2062
2063 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2064 EXPECT_VALID(lib);
2065 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2066
2067 const char* kReloadScript =
2068 "enum Fruit {\n"
2069 " Apple,\n"
2070 " Banana,\n"
2071 "}\n"
2072 "var x;\n"
2073 "main() {\n"
2074 " if (identical(x, Fruit.Banana)) {\n"
2075 " return 'yes';\n"
2076 " } else {\n"
2077 " return 'no';\n"
2078 " }\n"
2079 "}\n";
2080
2081 lib = TestCase::ReloadTestScript(kReloadScript);
2082 EXPECT_VALID(lib);
2083 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
2084}
2085
2086TEST_CASE(IsolateReload_EnumReorderIdentical) {
2087 const char* kScript =
2088 "enum Fruit {\n"
2089 " Apple,\n"
2090 " Banana,\n"
2091 "}\n"
2092 "var x;\n"
2093 "main() {\n"
2094 " x = Fruit.Banana;\n"
2095 " return Fruit.Apple.toString();\n"
2096 "}\n";
2097
2098 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2099 EXPECT_VALID(lib);
2100 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2101
2102 const char* kReloadScript =
2103 "enum Fruit {\n"
2104 " Banana,\n"
2105 " Apple,\n"
2106 "}\n"
2107 "var x;\n"
2108 "main() {\n"
2109 " if (identical(x, Fruit.Banana)) {\n"
2110 " return 'yes';\n"
2111 " } else {\n"
2112 " return 'no';\n"
2113 " }\n"
2114 "}\n";
2115
2116 lib = TestCase::ReloadTestScript(kReloadScript);
2117 EXPECT_VALID(lib);
2118 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
2119}
2120
2121TEST_CASE(IsolateReload_EnumAddition) {
2122 const char* kScript =
2123 "enum Fruit {\n"
2124 " Apple,\n"
2125 " Banana,\n"
2126 "}\n"
2127 "var x;\n"
2128 "main() {\n"
2129 " return Fruit.Apple.toString();\n"
2130 "}\n";
2131
2132 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2133 EXPECT_VALID(lib);
2134 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2135
2136 const char* kReloadScript =
2137 "enum Fruit {\n"
2138 " Apple,\n"
2139 " Cantalope,\n"
2140 " Banana,\n"
2141 "}\n"
2142 "var x;\n"
2143 "main() {\n"
2144 " String r = '${Fruit.Apple.index}/${Fruit.Apple} ';\n"
2145 " r += '${Fruit.Cantalope.index}/${Fruit.Cantalope} ';\n"
2146 " r += '${Fruit.Banana.index}/${Fruit.Banana}';\n"
2147 " return r;\n"
2148 "}\n";
2149
2150 lib = TestCase::ReloadTestScript(kReloadScript);
2151 EXPECT_VALID(lib);
2152 EXPECT_STREQ("0/Fruit.Apple 1/Fruit.Cantalope 2/Fruit.Banana",
2153 SimpleInvokeStr(lib, "main"));
2154}
2155
2156TEST_CASE(IsolateReload_EnumToNotEnum) {
2157 const char* kScript =
2158 "enum Fruit {\n"
2159 " Apple\n"
2160 "}\n"
2161 "main() {\n"
2162 " return Fruit.Apple.toString();\n"
2163 "}\n";
2164
2165 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2166 EXPECT_VALID(lib);
2167 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2168
2169 const char* kReloadScript =
2170 "class Fruit {\n"
2171 " final int zero = 0;\n"
2172 "}\n"
2173 "main() {\n"
2174 " return new Fruit().zero.toString();\n"
2175 "}\n";
2176
2177 Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
2178 EXPECT_ERROR(result, "Enum class cannot be redefined to be a non-enum class");
2179}
2180
2181TEST_CASE(IsolateReload_NotEnumToEnum) {
2182 const char* kScript =
2183 "class Fruit {\n"
2184 " final int zero = 0;\n"
2185 "}\n"
2186 "main() {\n"
2187 " return new Fruit().zero.toString();\n"
2188 "}\n";
2189
2190 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2191 EXPECT_VALID(lib);
2192 EXPECT_STREQ("0", SimpleInvokeStr(lib, "main"));
2193
2194 const char* kReloadScript =
2195 "enum Fruit {\n"
2196 " Apple\n"
2197 "}\n"
2198 "main() {\n"
2199 " return Fruit.Apple.toString();\n"
2200 "}\n";
2201
2202 Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
2203 EXPECT_ERROR(result, "Class cannot be redefined to be a enum class");
2204}
2205
2206TEST_CASE(IsolateReload_EnumDelete) {
2207 const char* kScript =
2208 "enum Fruit {\n"
2209 " Apple,\n"
2210 " Banana,\n"
2211 " Cantalope,\n"
2212 "}\n"
2213 "var x;\n"
2214 "main() {\n"
2215 " x = Fruit.Cantalope;\n"
2216 " return Fruit.Apple.toString();\n"
2217 "}\n";
2218
2219 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2220 EXPECT_VALID(lib);
2221 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2222
2223 // Delete 'Cantalope' but make sure that we can still invoke toString,
2224 // and access the hashCode and index properties.
2225
2226 const char* kReloadScript =
2227 "enum Fruit {\n"
2228 " Apple,\n"
2229 " Banana,\n"
2230 "}\n"
2231 "var x;\n"
2232 "main() {\n"
2233 " String r = '$x ${x.hashCode is int} ${x.index}';\n"
2234 " return r;\n"
2235 "}\n";
2236
2237 lib = TestCase::ReloadTestScript(kReloadScript);
2238 EXPECT_VALID(lib);
2239 EXPECT_STREQ("Deleted enum value from Fruit true -1",
2240 SimpleInvokeStr(lib, "main"));
2241}
2242
2243TEST_CASE(IsolateReload_EnumIdentityReload) {
2244 const char* kScript =
2245 "enum Fruit {\n"
2246 " Apple,\n"
2247 " Banana,\n"
2248 " Cantalope,\n"
2249 "}\n"
2250 "var x;\n"
2251 "var y;\n"
2252 "var z;\n"
2253 "var w;\n"
2254 "main() {\n"
2255 " x = { Fruit.Apple: Fruit.Apple.index,\n"
2256 " Fruit.Banana: Fruit.Banana.index,\n"
2257 " Fruit.Cantalope: Fruit.Cantalope.index};\n"
2258 " y = Fruit.Apple;\n"
2259 " z = Fruit.Banana;\n"
2260 " w = Fruit.Cantalope;\n"
2261 " return Fruit.Apple.toString();\n"
2262 "}\n";
2263
2264 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2265 EXPECT_VALID(lib);
2266 EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
2267
2268 const char* kReloadScript =
2269 "enum Fruit {\n"
2270 " Apple,\n"
2271 " Banana,\n"
2272 " Cantalope,\n"
2273 "}\n"
2274 "var x;\n"
2275 "var y;\n"
2276 "var z;\n"
2277 "var w;\n"
2278 "bool identityCheck(Fruit f, int index) {\n"
2279 " return identical(Fruit.values[index], f);\n"
2280 "}\n"
2281 "main() {\n"
2282 " String r = '';\n"
2283 " x.forEach((key, value) {\n"
2284 " r += '${identityCheck(key, value)} ';\n"
2285 " });\n"
2286 " r += '${x[Fruit.Apple] == Fruit.Apple.index} ';\n"
2287 " r += '${x[Fruit.Banana] == Fruit.Banana.index} ';\n"
2288 " r += '${x[Fruit.Cantalope] == Fruit.Cantalope.index} ';\n"
2289 " r += '${identical(y, Fruit.values[x[Fruit.Apple]])} ';\n"
2290 " r += '${identical(z, Fruit.values[x[Fruit.Banana]])} ';\n"
2291 " r += '${identical(w, Fruit.values[x[Fruit.Cantalope]])} ';\n"
2292 " return r;\n"
2293 "}\n";
2294
2295 lib = TestCase::ReloadTestScript(kReloadScript);
2296 EXPECT_VALID(lib);
2297 EXPECT_STREQ("true true true true true true true true true ",
2298 SimpleInvokeStr(lib, "main"));
2299}
2300
2301TEST_CASE(IsolateReload_ConstantIdentical) {
2302 const char* kScript =
2303 "class Fruit {\n"
2304 " final String name;\n"
2305 " const Fruit(this.name);\n"
2306 " String toString() => name;\n"
2307 "}\n"
2308 "var x;\n"
2309 "main() {\n"
2310 " x = const Fruit('Pear');\n"
2311 " return x.toString();\n"
2312 "}\n";
2313
2314 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2315 EXPECT_VALID(lib);
2316 EXPECT_STREQ("Pear", SimpleInvokeStr(lib, "main"));
2317
2318 const char* kReloadScript =
2319 "class Fruit {\n"
2320 " final String name;\n"
2321 " const Fruit(this.name);\n"
2322 " String toString() => name;\n"
2323 "}\n"
2324 "var x;\n"
2325 "main() {\n"
2326 " if (identical(x, const Fruit('Pear'))) {\n"
2327 " return 'yes';\n"
2328 " } else {\n"
2329 " return 'no';\n"
2330 " }\n"
2331 "}\n";
2332
2333 lib = TestCase::ReloadTestScript(kReloadScript);
2334 EXPECT_VALID(lib);
2335 EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
2336}
2337
2338TEST_CASE(IsolateReload_EnumValuesToString) {
2339 const char* kScript =
2340 "enum Fruit {\n"
2341 " Apple,\n"
2342 " Banana,\n"
2343 "}\n"
2344 "var x;\n"
2345 "main() {\n"
2346 " String r = '';\n"
2347 " r += Fruit.Apple.toString();\n"
2348 " r += ' ';\n"
2349 " r += Fruit.Banana.toString();\n"
2350 " return r;\n"
2351 "}\n";
2352
2353 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2354 EXPECT_VALID(lib);
2355 EXPECT_STREQ("Fruit.Apple Fruit.Banana", SimpleInvokeStr(lib, "main"));
2356
2357 // Insert 'Cantalope'.
2358
2359 const char* kReloadScript =
2360 "enum Fruit {\n"
2361 " Apple,\n"
2362 " Cantalope,\n"
2363 " Banana\n"
2364 "}\n"
2365 "var x;\n"
2366 "main() {\n"
2367 " String r = '';\n"
2368 " r += Fruit.Apple.toString();\n"
2369 " r += ' ';\n"
2370 " r += Fruit.Cantalope.toString();\n"
2371 " r += ' ';\n"
2372 " r += Fruit.Banana.toString();\n"
2373 " return r;\n"
2374 "}\n";
2375
2376 lib = TestCase::ReloadTestScript(kReloadScript);
2377 EXPECT_VALID(lib);
2378 EXPECT_STREQ("Fruit.Apple Fruit.Cantalope Fruit.Banana",
2379 SimpleInvokeStr(lib, "main"));
2380}
2381
2382ISOLATE_UNIT_TEST_CASE(IsolateReload_DirectSubclasses_Success) {
2383 Object& new_subclass = Object::Handle();
2384 String& name = String::Handle();
2385
2386 // Lookup the Stopwatch class by name from the dart core library.
2387 ObjectStore* object_store = Isolate::Current()->object_store();
2388 const Library& core_lib = Library::Handle(object_store->core_library());
2389 name = String::New("Stopwatch");
2390 const Class& stopwatch_cls = Class::Handle(core_lib.LookupClass(name));
2391
2392 // Keep track of how many subclasses an Stopwatch has.
2393 auto& subclasses =
2394 GrowableObjectArray::Handle(stopwatch_cls.direct_subclasses());
2395 intptr_t saved_subclass_count = subclasses.IsNull() ? 0 : subclasses.Length();
2396
2397 const char* kScript =
2398 "class AStopwatch extends Stopwatch {\n"
2399 "}\n"
2400 "main() {\n"
2401 " new AStopwatch();\n" // Force finalization.
2402 " return 1;\n"
2403 "}\n";
2404
2405 {
2406 TransitionVMToNative transition(thread);
2407 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2408 EXPECT_VALID(lib);
2409 EXPECT_EQ(1, SimpleInvoke(lib, "main"));
2410 }
2411
2412 // Stopwatch has one non-core subclass.
2413 subclasses = stopwatch_cls.direct_subclasses();
2414 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
2415
2416 // The new subclass is named AStopwatch.
2417 new_subclass = subclasses.At(subclasses.Length() - 1);
2418 name = Class::Cast(new_subclass).Name();
2419 EXPECT_STREQ("AStopwatch", name.ToCString());
2420
2421 const char* kReloadScript =
2422 "class AStopwatch {\n"
2423 "}\n"
2424 "class BStopwatch extends Stopwatch {\n"
2425 "}\n"
2426 "main() {\n"
2427 " new AStopwatch();\n" // Force finalization.
2428 " new BStopwatch();\n" // Force finalization.
2429 " return 2;\n"
2430 "}\n";
2431
2432 {
2433 TransitionVMToNative transition(thread);
2434 Dart_Handle lib = TestCase::ReloadTestScript(kReloadScript);
2435 EXPECT_VALID(lib);
2436 EXPECT_EQ(2, SimpleInvoke(lib, "main"));
2437 }
2438
2439 // Stopwatch still has only one non-core subclass (AStopwatch is gone).
2440 subclasses = stopwatch_cls.direct_subclasses();
2441 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
2442
2443 // The new subclass is named BStopwatch.
2444 new_subclass = subclasses.At(subclasses.Length() - 1);
2445 name = Class::Cast(new_subclass).Name();
2446 EXPECT_STREQ("BStopwatch", name.ToCString());
2447}
2448
2449ISOLATE_UNIT_TEST_CASE(IsolateReload_DirectSubclasses_GhostSubclass) {
2450 Object& new_subclass = Object::Handle();
2451 String& name = String::Handle();
2452
2453 // Lookup the Stopwatch class by name from the dart core library.
2454 ObjectStore* object_store = Isolate::Current()->object_store();
2455 const Library& core_lib = Library::Handle(object_store->core_library());
2456 name = String::New("Stopwatch");
2457 const Class& stopwatch_cls = Class::Handle(core_lib.LookupClass(name));
2458
2459 // Keep track of how many subclasses an Stopwatch has.
2460 auto& subclasses =
2461 GrowableObjectArray::Handle(stopwatch_cls.direct_subclasses());
2462 intptr_t saved_subclass_count = subclasses.IsNull() ? 0 : subclasses.Length();
2463
2464 const char* kScript =
2465 "class AStopwatch extends Stopwatch {\n"
2466 "}\n"
2467 "main() {\n"
2468 " new AStopwatch();\n" // Force finalization.
2469 " return 1;\n"
2470 "}\n";
2471
2472 {
2473 TransitionVMToNative transition(thread);
2474 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2475 EXPECT_VALID(lib);
2476 EXPECT_EQ(1, SimpleInvoke(lib, "main"));
2477 }
2478
2479 // Stopwatch has one new subclass.
2480 subclasses = stopwatch_cls.direct_subclasses();
2481 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
2482
2483 // The new subclass is named AStopwatch.
2484 new_subclass = subclasses.At(subclasses.Length() - 1);
2485 name = Class::Cast(new_subclass).Name();
2486 EXPECT_STREQ("AStopwatch", name.ToCString());
2487
2488 const char* kReloadScript =
2489 "class BStopwatch extends Stopwatch {\n"
2490 "}\n"
2491 "main() {\n"
2492 " new BStopwatch();\n" // Force finalization.
2493 " return 2;\n"
2494 "}\n";
2495
2496 {
2497 TransitionVMToNative transition(thread);
2498 Dart_Handle lib = TestCase::ReloadTestScript(kReloadScript);
2499 EXPECT_VALID(lib);
2500 EXPECT_EQ(2, SimpleInvoke(lib, "main"));
2501 }
2502
2503 // Stopwatch has two non-core subclasses.
2504 subclasses = stopwatch_cls.direct_subclasses();
2505 EXPECT_EQ(saved_subclass_count + 2, subclasses.Length());
2506
2507 // The non-core subclasses are AStopwatch and BStopwatch.
2508 new_subclass = subclasses.At(subclasses.Length() - 2);
2509 name = Class::Cast(new_subclass).Name();
2510 EXPECT_STREQ("AStopwatch", name.ToCString());
2511
2512 new_subclass = subclasses.At(subclasses.Length() - 1);
2513 name = Class::Cast(new_subclass).Name();
2514 EXPECT_STREQ("BStopwatch", name.ToCString());
2515}
2516
2517// Make sure that we restore the direct subclass info when we revert.
2518ISOLATE_UNIT_TEST_CASE(IsolateReload_DirectSubclasses_Failure) {
2519 Object& new_subclass = Object::Handle();
2520 String& name = String::Handle();
2521
2522 // Lookup the Stopwatch class by name from the dart core library.
2523 ObjectStore* object_store = Isolate::Current()->object_store();
2524 const Library& core_lib = Library::Handle(object_store->core_library());
2525 name = String::New("Stopwatch");
2526 const Class& stopwatch_cls = Class::Handle(core_lib.LookupClass(name));
2527
2528 // Keep track of how many subclasses an Stopwatch has.
2529 auto& subclasses =
2530 GrowableObjectArray::Handle(stopwatch_cls.direct_subclasses());
2531 intptr_t saved_subclass_count = subclasses.IsNull() ? 0 : subclasses.Length();
2532
2533 const char* kScript =
2534 "class AStopwatch extends Stopwatch {\n"
2535 "}\n"
2536 "class Foo {\n"
2537 " final a;\n"
2538 " Foo(this.a);\n"
2539 "}\n"
2540 "main() {\n"
2541 " new AStopwatch();\n" // Force finalization.
2542 " new Foo(5);\n" // Force finalization.
2543 " return 1;\n"
2544 "}\n";
2545
2546 {
2547 TransitionVMToNative transition(thread);
2548 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2549 EXPECT_VALID(lib);
2550 EXPECT_EQ(1, SimpleInvoke(lib, "main"));
2551 }
2552
2553 // Stopwatch has one non-core subclass...
2554 subclasses = stopwatch_cls.direct_subclasses();
2555 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
2556
2557 // ... and the non-core subclass is named AStopwatch.
2558 subclasses = stopwatch_cls.direct_subclasses();
2559 new_subclass = subclasses.At(subclasses.Length() - 1);
2560 name = Class::Cast(new_subclass).Name();
2561 EXPECT_STREQ("AStopwatch", name.ToCString());
2562
2563 // Attempt to reload with a bogus script.
2564 const char* kReloadScript =
2565 "class BStopwatch extends Stopwatch {\n"
2566 "}\n"
2567 "class Foo {\n"
2568 " final a kjsdf ksjdf ;\n" // When we refinalize, we get an error.
2569 " Foo(this.a);\n"
2570 "}\n"
2571 "main() {\n"
2572 " new BStopwatch();\n" // Force finalization.
2573 " new Foo(5);\n" // Force finalization.
2574 " return 2;\n"
2575 "}\n";
2576
2577 {
2578 TransitionVMToNative transition(thread);
2579 Dart_Handle lib = TestCase::ReloadTestScript(kReloadScript);
2580 EXPECT_ERROR(lib, "Expected ';' after this");
2581 }
2582
2583 // If we don't clean up the subclasses, we would find BStopwatch in
2584 // the list of subclasses, which would be bad. Make sure that
2585 // Stopwatch still has only one non-core subclass...
2586 subclasses = stopwatch_cls.direct_subclasses();
2587 EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
2588
2589 // ...and the non-core subclass is still named AStopwatch.
2590 new_subclass = subclasses.At(subclasses.Length() - 1);
2591 name = Class::Cast(new_subclass).Name();
2592 EXPECT_STREQ("AStopwatch", name.ToCString());
2593}
2594
2595// Tests reload succeeds when instance format changes.
2596// Change: Foo {a, b, c:42} -> Foo {c:42}
2597// Validate: c keeps the value in the retained Foo object.
2598TEST_CASE(IsolateReload_ChangeInstanceFormat0) {
2599 const char* kScript =
2600 "class Foo {\n"
2601 " var a;\n"
2602 " var b;\n"
2603 " var c;\n"
2604 "}\n"
2605 "var f;\n"
2606 "main() {\n"
2607 " f = new Foo();\n"
2608 " f.c = 42;\n"
2609 " return f.c;\n"
2610 "}\n";
2611
2612 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2613 EXPECT_VALID(lib);
2614 EXPECT_EQ(42, SimpleInvoke(lib, "main"));
2615
2616 const char* kReloadScript =
2617 "class Foo {\n"
2618 " var c;\n"
2619 "}\n"
2620 "var f;\n"
2621 "main() {\n"
2622 " return f.c;\n"
2623 "}\n";
2624
2625 lib = TestCase::ReloadTestScript(kReloadScript);
2626 EXPECT_VALID(lib);
2627 EXPECT_EQ(42, SimpleInvoke(lib, "main"));
2628}
2629
2630// Tests reload succeeds when instance format changes.
2631// Change: Foo {} -> Foo {c:null}
2632// Validate: c is initialized to null the retained Foo object.
2633TEST_CASE(IsolateReload_ChangeInstanceFormat1) {
2634 const char* kScript =
2635 "class Foo {\n"
2636 "}\n"
2637 "var f;\n"
2638 "main() {\n"
2639 " f = new Foo();\n"
2640 " return 42;\n"
2641 "}\n";
2642
2643 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2644 EXPECT_VALID(lib);
2645 EXPECT_EQ(42, SimpleInvoke(lib, "main"));
2646
2647 const char* kReloadScript =
2648 "class Foo {\n"
2649 " var c;\n"
2650 "}\n"
2651 "var f;\n"
2652 "main() {\n"
2653 " return (f.c == null) ? 42: 21;\n"
2654 "}\n";
2655
2656 lib = TestCase::ReloadTestScript(kReloadScript);
2657 EXPECT_VALID(lib);
2658 EXPECT_EQ(42, SimpleInvoke(lib, "main"));
2659}
2660
2661// Tests reload succeeds when instance format changes.
2662// Change: Foo {c:42} -> Foo {}
2663// Validate: running the after script fails.
2664TEST_CASE(IsolateReload_ChangeInstanceFormat2) {
2665 const char* kScript =
2666 "class Foo {\n"
2667 " var c;\n"
2668 "}\n"
2669 "var f;\n"
2670 "main() {\n"
2671 " f = new Foo();\n"
2672 " f.c = 42;\n"
2673 " return f.c;\n"
2674 "}\n";
2675
2676 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2677 EXPECT_VALID(lib);
2678 EXPECT_EQ(42, SimpleInvoke(lib, "main"));
2679
2680 const char* kReloadScript =
2681 "class Foo {\n"
2682 "}\n"
2683 "var f;\n"
2684 "main() {\n"
2685 " try {\n"
2686 " return f.c;\n"
2687 " } catch (e) {\n"
2688 " return 24;\n"
2689 " }\n"
2690 "}\n";
2691
2692 lib = TestCase::ReloadTestScript(kReloadScript);
2693 EXPECT_VALID(lib);
2694 EXPECT_EQ(24, SimpleInvoke(lib, "main"));
2695}
2696
2697// Tests reload succeeds when instance format changes.
2698// Change: Foo {a, b, c:42, d} -> Foo {c:42, g}
2699// Validate: c keeps the value in the retained Foo object.
2700TEST_CASE(IsolateReload_ChangeInstanceFormat3) {
2701 const char* kScript =
2702 "class Foo<A,B> {\n"
2703 " var a;\n"
2704 " var b;\n"
2705 " var c;\n"
2706 " var d;\n"
2707 "}\n"
2708 "var f;\n"
2709 "main() {\n"
2710 " f = new Foo();\n"
2711 " f.a = 1;\n"
2712 " f.b = 2;\n"
2713 " f.c = 3;\n"
2714 " f.d = 4;\n"
2715 " return f.c;\n"
2716 "}\n";
2717
2718 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2719 EXPECT_VALID(lib);
2720 EXPECT_EQ(3, SimpleInvoke(lib, "main"));
2721
2722 const char* kReloadScript =
2723 "class Foo<A,B> {\n"
2724 " var c;\n"
2725 " var g;\n"
2726 "}\n"
2727 "var f;\n"
2728 "main() {\n"
2729 " return f.c;\n"
2730 "}\n";
2731
2732 lib = TestCase::ReloadTestScript(kReloadScript);
2733 EXPECT_VALID(lib);
2734 EXPECT_EQ(3, SimpleInvoke(lib, "main"));
2735}
2736
2737// Tests reload succeeds when instance format changes.
2738// Change: Bar {c:42}, Foo : Bar {d, e} -> Foo {c:42}
2739// Validate: c keeps the value in the retained Foo object.
2740TEST_CASE(IsolateReload_ChangeInstanceFormat4) {
2741 const char* kScript =
2742 "class Bar{\n"
2743 " var c;\n"
2744 "}\n"
2745 "class Foo extends Bar{\n"
2746 " var d;\n"
2747 " var e;\n"
2748 "}\n"
2749 "var f;\n"
2750 "main() {\n"
2751 " f = new Foo();\n"
2752 " f.c = 44;\n"
2753 " return f.c;\n"
2754 "}\n";
2755
2756 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2757 EXPECT_VALID(lib);
2758 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
2759
2760 const char* kReloadScript =
2761 "class Foo {\n"
2762 " var c;\n"
2763 "}\n"
2764 "var f;\n"
2765 "main() {\n"
2766 " return f.c;\n"
2767 "}\n";
2768
2769 lib = TestCase::ReloadTestScript(kReloadScript);
2770 EXPECT_VALID(lib);
2771 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
2772}
2773
2774// Tests reload succeeds when instance format changes.
2775// Change: Bar {a, b}, Foo : Bar {c:42} -> Bar {c:42}, Foo : Bar {}
2776// Validate: c keeps the value in the retained Foo object.
2777TEST_CASE(IsolateReload_ChangeInstanceFormat5) {
2778 const char* kScript =
2779 "class Bar{\n"
2780 " var a;\n"
2781 " var b;\n"
2782 "}\n"
2783 "class Foo extends Bar{\n"
2784 " var c;\n"
2785 "}\n"
2786 "var f;\n"
2787 "main() {\n"
2788 " f = new Foo();\n"
2789 " f.c = 44;\n"
2790 " return f.c;\n"
2791 "}\n";
2792
2793 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2794 EXPECT_VALID(lib);
2795 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
2796
2797 const char* kReloadScript =
2798 "class Bar{\n"
2799 " var c;\n"
2800 "}\n"
2801 "class Foo extends Bar {\n"
2802 "}\n"
2803 "var f;\n"
2804 "main() {\n"
2805 " return f.c;\n"
2806 "}\n";
2807
2808 lib = TestCase::ReloadTestScript(kReloadScript);
2809 EXPECT_VALID(lib);
2810 EXPECT_EQ(44, SimpleInvoke(lib, "main"));
2811}
2812
2813// Tests reload fails when type parameters change.
2814// Change: Foo<A,B> {a, b} -> Foo<A> {a}
2815// Validate: the right error message is returned.
2816TEST_CASE(IsolateReload_ChangeInstanceFormat6) {
2817 const char* kScript =
2818 "class Foo<A, B> {\n"
2819 " var a;\n"
2820 " var b;\n"
2821 "}\n"
2822 "main() {\n"
2823 " new Foo();\n"
2824 " return 43;\n"
2825 "}\n";
2826
2827 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2828 EXPECT_VALID(lib);
2829 EXPECT_EQ(43, SimpleInvoke(lib, "main"));
2830
2831 const char* kReloadScript =
2832 "class Foo<A> {\n"
2833 " var a;\n"
2834 "}\n";
2835 lib = TestCase::ReloadTestScript(kReloadScript);
2836 EXPECT_ERROR(lib, "type parameters have changed");
2837}
2838
2839// Tests reload succeeds when type parameters are changed for allocated class.
2840// Change: Foo<A,B> {a, b} -> Foo<A> {a}
2841// Validate: return value from main is correct.
2842// Please note: This test works because no instances are created from Foo.
2843TEST_CASE(IsolateReload_ChangeInstanceFormat7) {
2844 const char* kScript =
2845 "class Foo<A, B> {\n"
2846 " var a;\n"
2847 " var b;\n"
2848 "}\n";
2849
2850 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2851 EXPECT_VALID(lib);
2852
2853 const char* kReloadScript =
2854 "class Foo<A> {\n"
2855 " var a;\n"
2856 "}\n";
2857 lib = TestCase::ReloadTestScript(kReloadScript);
2858 EXPECT_VALID(lib);
2859}
2860
2861// Regression for handle sharing bug: Change the shape of two classes and see
2862// that their instances don't change class.
2863TEST_CASE(IsolateReload_ChangeInstanceFormat8) {
2864 const char* kScript =
2865 "class A{\n"
2866 " var x;\n"
2867 "}\n"
2868 "class B {\n"
2869 " var x, y, z, w;\n"
2870 "}\n"
2871 "var a, b;\n"
2872 "main() {\n"
2873 " a = new A();\n"
2874 " b = new B();\n"
2875 " return '$a $b';\n"
2876 "}\n";
2877
2878 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2879 EXPECT_VALID(lib);
2880 EXPECT_STREQ("Instance of 'A' Instance of 'B'", SimpleInvokeStr(lib, "main"));
2881
2882 const char* kReloadScript =
2883 "class A{\n"
2884 " var x, y;\n"
2885 "}\n"
2886 "class B {\n"
2887 " var x, y, z, w, v;\n"
2888 "}\n"
2889 "var a, b;\n"
2890 "main() {\n"
2891 " return '$a $b';\n"
2892 "}\n";
2893
2894 lib = TestCase::ReloadTestScript(kReloadScript);
2895 EXPECT_VALID(lib);
2896 EXPECT_STREQ("Instance of 'A' Instance of 'B'", SimpleInvokeStr(lib, "main"));
2897}
2898
2899// Tests reload fails when type arguments change.
2900// Change: Baz extends Foo<String> -> Baz extends Bar<String, double>
2901// Validate: the right error message is returned.
2902TEST_CASE(IsolateReload_ChangeInstanceFormat9) {
2903 const char* kScript =
2904 "class Foo<A> {\n"
2905 " var a;\n"
2906 "}\n"
2907 "class Bar<B, C> extends Foo<B> {}\n"
2908 "class Baz extends Foo<String> {}"
2909 "main() {\n"
2910 " new Baz();\n"
2911 " return 43;\n"
2912 "}\n";
2913
2914 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2915 EXPECT_VALID(lib);
2916 EXPECT_EQ(43, SimpleInvoke(lib, "main"));
2917
2918 const char* kReloadScript =
2919 "class Foo<A> {\n"
2920 " var a;\n"
2921 "}\n"
2922 "class Bar<B, C> extends Foo<B> {}\n"
2923 "class Baz extends Bar<String, double> {}"
2924 "main() {\n"
2925 " new Baz();\n"
2926 " return 43;\n"
2927 "}\n";
2928 lib = TestCase::ReloadTestScript(kReloadScript);
2929 EXPECT_ERROR(lib, "type parameters have changed");
2930}
2931
2932TEST_CASE(IsolateReload_ShapeChangeRetainsHash) {
2933 const char* kScript =
2934 "class A{\n"
2935 " var x;\n"
2936 "}\n"
2937 "var a, hash1, hash2;\n"
2938 "main() {\n"
2939 " a = new A();\n"
2940 " hash1 = a.hashCode;\n"
2941 " return 'okay';\n"
2942 "}\n";
2943
2944 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2945 EXPECT_VALID(lib);
2946 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
2947
2948 const char* kReloadScript =
2949 "class A{\n"
2950 " var x, y, z;\n"
2951 "}\n"
2952 "var a, hash1, hash2;\n"
2953 "main() {\n"
2954 " hash2 = a.hashCode;\n"
2955 " return (hash1 == hash2).toString();\n"
2956 "}\n";
2957
2958 lib = TestCase::ReloadTestScript(kReloadScript);
2959 EXPECT_VALID(lib);
2960 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
2961}
2962
2963TEST_CASE(IsolateReload_ShapeChangeRetainsHash_Const) {
2964 const char* kScript =
2965 "class A {\n"
2966 " final x;\n"
2967 " const A(this.x);\n"
2968 "}\n"
2969 "var a, hash1, hash2;\n"
2970 "main() {\n"
2971 " a = const A(1);\n"
2972 " hash1 = a.hashCode;\n"
2973 " return 'okay';\n"
2974 "}\n";
2975
2976 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
2977 EXPECT_VALID(lib);
2978 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
2979
2980 const char* kReloadScript =
2981 "class A {\n"
2982 " final x, y, z;\n"
2983 " const A(this.x, this.y, this.z);\n"
2984 "}\n"
2985 "var a, hash1, hash2;\n"
2986 "main() {\n"
2987 " hash2 = a.hashCode;\n"
2988 " return (hash1 == hash2).toString();\n"
2989 "}\n";
2990
2991 lib = TestCase::ReloadTestScript(kReloadScript);
2992 EXPECT_VALID(lib);
2993 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
2994}
2995
2996TEST_CASE(IsolateReload_ShapeChange_Const_AddSlot) {
2997 // On IA32, instructions can contain direct pointers to const objects. We need
2998 // to be careful that if the const objects are reallocated because of a shape
2999 // change, they are allocated old. Because instructions normally contain
3000 // pointers only to old objects, the scavenger does not bother to ensure code
3001 // pages are writable when visiting the remembered set. Visiting the
3002 // remembered involes writing to update the pointer for any target that gets
3003 // promoted.
3004 const char* kScript = R"(
3005 import 'file:///test:isolate_reload_helper';
3006 class A {
3007 final x;
3008 const A(this.x);
3009 }
3010 var a;
3011 main() {
3012 a = const A(1);
3013 collectNewSpace();
3014 return 'okay';
3015 }
3016 )";
3017
3018 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3019 EXPECT_VALID(lib);
3020 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
3021
3022 const char* kReloadScript = R"(
3023 import 'file:///test:isolate_reload_helper';
3024 class A {
3025 final x, y, z;
3026 const A(this.x, this.y, this.z);
3027 }
3028 var a;
3029 main() {
3030 a = const A(1, null, null);
3031 collectNewSpace();
3032 return 'okay';
3033 }
3034 )";
3035
3036 lib = TestCase::ReloadTestScript(kReloadScript);
3037 EXPECT_VALID(lib);
3038 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
3039
3040 const char* kReloadScript2 = R"(
3041 import 'file:///test:isolate_reload_helper';
3042 class A {
3043 final x, y, z, w, u;
3044 const A(this.x, this.y, this.z, this.w, this.u);
3045 }
3046 var a;
3047 main() {
3048 a = const A(1, null, null, null, null);
3049 collectNewSpace();
3050 return 'okay';
3051 }
3052 )";
3053
3054 lib = TestCase::ReloadTestScript(kReloadScript2);
3055 EXPECT_VALID(lib);
3056 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
3057}
3058
3059TEST_CASE(IsolateReload_ShapeChange_Const_RemoveSlot) {
3060 const char* kScript = R"(
3061 import 'file:///test:isolate_reload_helper';
3062 class A {
3063 final x, y, z;
3064 const A(this.x, this.y, this.z);
3065 }
3066 var a;
3067 main() {
3068 a = const A(1, 2, 3);
3069 collectNewSpace();
3070 return 'okay';
3071 }
3072 )";
3073
3074 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3075 EXPECT_VALID(lib);
3076 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
3077
3078 const char* kReloadScript = R"(
3079 import 'file:///test:isolate_reload_helper';
3080 class A {
3081 final x, y;
3082 const A(this.x, this.y);
3083 }
3084 var a;
3085 main() {
3086 a = const A(1, null);
3087 collectNewSpace();
3088 return 'okay';
3089 }
3090 )";
3091
3092 lib = TestCase::ReloadTestScript(kReloadScript);
3093 EXPECT_ERROR(lib,
3094 "Const class cannot remove fields: "
3095 "Library:'file:///test-lib' Class: A");
3096
3097 // Rename is seen by the VM is unrelated add and remove.
3098 const char* kReloadScript2 = R"(
3099 import 'file:///test:isolate_reload_helper';
3100 class A {
3101 final x, y, w;
3102 const A(this.x, this.y, this.w);
3103 }
3104 var a;
3105 main() {
3106 a = const A(1, null, null);
3107 collectNewSpace();
3108 return 'okay';
3109 }
3110 )";
3111
3112 lib = TestCase::ReloadTestScript(kReloadScript2);
3113 EXPECT_ERROR(lib,
3114 "Const class cannot remove fields: "
3115 "Library:'file:///test-lib' Class: A");
3116}
3117
3118TEST_CASE(IsolateReload_ConstToNonConstClass) {
3119 const char* kScript = R"(
3120 class A {
3121 final dynamic x;
3122 const A(this.x);
3123 }
3124 dynamic a;
3125 main() {
3126 a = const A(1);
3127 return 'okay';
3128 }
3129 )";
3130
3131 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3132 EXPECT_VALID(lib);
3133 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
3134
3135 const char* kReloadScript = R"(
3136 class A {
3137 dynamic x;
3138 A(this.x);
3139 }
3140 dynamic a;
3141 main() {
3142 a.x = 10;
3143 }
3144 )";
3145
3146 lib = TestCase::ReloadTestScript(kReloadScript);
3147 EXPECT_ERROR(lib,
3148 "Const class cannot become non-const: "
3149 "Library:'file:///test-lib' Class: A");
3150}
3151
3152TEST_CASE(IsolateReload_ConstToNonConstClass_Empty) {
3153 const char* kScript = R"(
3154 class A {
3155 const A();
3156 }
3157 dynamic a;
3158 main() {
3159 a = const A();
3160 return 'okay';
3161 }
3162 )";
3163
3164 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3165 EXPECT_VALID(lib);
3166 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
3167
3168 const char* kReloadScript = R"(
3169 class A {
3170 dynamic x;
3171 A(this.x);
3172 }
3173 dynamic a;
3174 main() {
3175 a.x = 10;
3176 }
3177 )";
3178
3179 lib = TestCase::ReloadTestScript(kReloadScript);
3180 EXPECT_ERROR(lib,
3181 "Const class cannot become non-const: "
3182 "Library:'file:///test-lib' Class: A");
3183}
3184
3185TEST_CASE(IsolateReload_StaticTearOffRetainsHash) {
3186 const char* kScript =
3187 "foo() {}\n"
3188 "var hash1, hash2;\n"
3189 "main() {\n"
3190 " hash1 = foo.hashCode;\n"
3191 " return 'okay';\n"
3192 "}\n";
3193
3194 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3195 EXPECT_VALID(lib);
3196 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
3197
3198 const char* kReloadScript =
3199 "foo() {}\n"
3200 "var hash1, hash2;\n"
3201 "main() {\n"
3202 " hash2 = foo.hashCode;\n"
3203 " return (hash1 == hash2).toString();\n"
3204 "}\n";
3205
3206 lib = TestCase::ReloadTestScript(kReloadScript);
3207 EXPECT_VALID(lib);
3208 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
3209}
3210
3211static bool NothingModifiedCallback(const char* url, int64_t since) {
3212 return false;
3213}
3214
3215TEST_CASE(IsolateReload_NoLibsModified) {
3216 const char* kImportScript = "importedFunc() => 'fancy';";
3217 TestCase::AddTestLib("test:lib1", kImportScript);
3218
3219 const char* kScript =
3220 "import 'test:lib1';\n"
3221 "main() {\n"
3222 " return importedFunc() + ' feast';\n"
3223 "}\n";
3224
3225 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3226 EXPECT_VALID(lib);
3227 EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
3228
3229 const char* kReloadImportScript = "importedFunc() => 'bossy';";
3230 TestCase::AddTestLib("test:lib1", kReloadImportScript);
3231
3232 const char* kReloadScript =
3233 "import 'test:lib1';\n"
3234 "main() {\n"
3235 " return importedFunc() + ' pants';\n"
3236 "}\n";
3237
3238 Dart_SetFileModifiedCallback(&NothingModifiedCallback);
3239 lib = TestCase::ReloadTestScript(kReloadScript);
3240 EXPECT_VALID(lib);
3241 Dart_SetFileModifiedCallback(NULL);
3242
3243 // No reload occurred because no files were "modified".
3244 EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
3245}
3246
3247static bool MainModifiedCallback(const char* url, int64_t since) {
3248 if ((strcmp(url, "test-lib") == 0) ||
3249 (strcmp(url, "file:///test-lib") == 0)) {
3250 return true;
3251 }
3252 return false;
3253}
3254
3255TEST_CASE(IsolateReload_MainLibModified) {
3256 const char* kImportScript = "importedFunc() => 'fancy';";
3257 TestCase::AddTestLib("test:lib1", kImportScript);
3258
3259 const char* kScript =
3260 "import 'test:lib1';\n"
3261 "main() {\n"
3262 " return importedFunc() + ' feast';\n"
3263 "}\n";
3264
3265 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3266 EXPECT_VALID(lib);
3267 EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
3268
3269 const char* kReloadImportScript = "importedFunc() => 'bossy';";
3270 TestCase::AddTestLib("test:lib1", kReloadImportScript);
3271
3272 const char* kReloadScript =
3273 "import 'test:lib1';\n"
3274 "main() {\n"
3275 " return importedFunc() + ' pants';\n"
3276 "}\n";
3277
3278 Dart_SetFileModifiedCallback(&MainModifiedCallback);
3279 lib = TestCase::ReloadTestScript(kReloadScript);
3280 EXPECT_VALID(lib);
3281 Dart_SetFileModifiedCallback(NULL);
3282
3283 // Imported library is not reloaded.
3284 EXPECT_STREQ("fancy pants", SimpleInvokeStr(lib, "main"));
3285}
3286
3287static bool ImportModifiedCallback(const char* url, int64_t since) {
3288 if (strcmp(url, "test:lib1") == 0) {
3289 return true;
3290 }
3291 return false;
3292}
3293
3294TEST_CASE(IsolateReload_ImportedLibModified) {
3295 const char* kImportScript = "importedFunc() => 'fancy';";
3296 TestCase::AddTestLib("test:lib1", kImportScript);
3297
3298 const char* kScript =
3299 "import 'test:lib1';\n"
3300 "main() {\n"
3301 " return importedFunc() + ' feast';\n"
3302 "}\n";
3303
3304 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3305 EXPECT_VALID(lib);
3306 EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
3307
3308 const char* kReloadImportScript = "importedFunc() => 'bossy';";
3309 TestCase::AddTestLib("test:lib1", kReloadImportScript);
3310
3311 const char* kReloadScript =
3312 "import 'test:lib1';\n"
3313 "main() {\n"
3314 " return importedFunc() + ' pants';\n"
3315 "}\n";
3316
3317 Dart_SetFileModifiedCallback(&ImportModifiedCallback);
3318 lib = TestCase::ReloadTestScript(kReloadScript);
3319 EXPECT_VALID(lib);
3320 Dart_SetFileModifiedCallback(NULL);
3321
3322 // Modification of an imported library propagates to the importing library.
3323 EXPECT_STREQ("bossy pants", SimpleInvokeStr(lib, "main"));
3324}
3325
3326TEST_CASE(IsolateReload_PrefixImportedLibModified) {
3327 const char* kImportScript = "importedFunc() => 'fancy';";
3328 TestCase::AddTestLib("test:lib1", kImportScript);
3329
3330 const char* kScript =
3331 "import 'test:lib1' as cobra;\n"
3332 "main() {\n"
3333 " return cobra.importedFunc() + ' feast';\n"
3334 "}\n";
3335
3336 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3337 EXPECT_VALID(lib);
3338 EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
3339
3340 const char* kReloadImportScript = "importedFunc() => 'bossy';";
3341 TestCase::AddTestLib("test:lib1", kReloadImportScript);
3342
3343 const char* kReloadScript =
3344 "import 'test:lib1' as cobra;\n"
3345 "main() {\n"
3346 " return cobra.importedFunc() + ' pants';\n"
3347 "}\n";
3348
3349 Dart_SetFileModifiedCallback(&ImportModifiedCallback);
3350 lib = TestCase::ReloadTestScript(kReloadScript);
3351 EXPECT_VALID(lib);
3352 Dart_SetFileModifiedCallback(NULL);
3353
3354 // Modification of an prefix-imported library propagates to the
3355 // importing library.
3356 EXPECT_STREQ("bossy pants", SimpleInvokeStr(lib, "main"));
3357}
3358
3359static bool ExportModifiedCallback(const char* url, int64_t since) {
3360 if (strcmp(url, "test:exportlib") == 0) {
3361 return true;
3362 }
3363 return false;
3364}
3365
3366TEST_CASE(IsolateReload_ExportedLibModified) {
3367 const char* kImportScript = "export 'test:exportlib';";
3368 TestCase::AddTestLib("test:importlib", kImportScript);
3369
3370 const char* kExportScript = "exportedFunc() => 'fancy';";
3371 TestCase::AddTestLib("test:exportlib", kExportScript);
3372
3373 const char* kScript =
3374 "import 'test:importlib';\n"
3375 "main() {\n"
3376 " return exportedFunc() + ' feast';\n"
3377 "}\n";
3378
3379 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3380 EXPECT_VALID(lib);
3381 EXPECT_STREQ("fancy feast", SimpleInvokeStr(lib, "main"));
3382
3383 const char* kReloadExportScript = "exportedFunc() => 'bossy';";
3384 TestCase::AddTestLib("test:exportlib", kReloadExportScript);
3385
3386 const char* kReloadScript =
3387 "import 'test:importlib';\n"
3388 "main() {\n"
3389 " return exportedFunc() + ' pants';\n"
3390 "}\n";
3391
3392 Dart_SetFileModifiedCallback(&ExportModifiedCallback);
3393 lib = TestCase::ReloadTestScript(kReloadScript);
3394 EXPECT_VALID(lib);
3395 Dart_SetFileModifiedCallback(NULL);
3396
3397 // Modification of an exported library propagates.
3398 EXPECT_STREQ("bossy pants", SimpleInvokeStr(lib, "main"));
3399}
3400
3401TEST_CASE(IsolateReload_SimpleConstFieldUpdate) {
3402 const char* kScript =
3403 "const value = 'a';\n"
3404 "main() {\n"
3405 " return 'value=${value}';\n"
3406 "}\n";
3407
3408 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3409 EXPECT_VALID(lib);
3410 EXPECT_STREQ("value=a", SimpleInvokeStr(lib, "main"));
3411
3412 const char* kReloadScript =
3413 "const value = 'b';\n"
3414 "main() {\n"
3415 " return 'value=${value}';\n"
3416 "}\n";
3417
3418 lib = TestCase::ReloadTestScript(kReloadScript);
3419 EXPECT_VALID(lib);
3420 EXPECT_STREQ("value=b", SimpleInvokeStr(lib, "main"));
3421}
3422
3423TEST_CASE(IsolateReload_ConstFieldUpdate) {
3424 const char* kScript =
3425 "const value = const Duration(seconds: 1);\n"
3426 "main() {\n"
3427 " return 'value=${value}';\n"
3428 "}\n";
3429
3430 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
3431 EXPECT_VALID(lib);
3432 EXPECT_STREQ("value=0:00:01.000000", SimpleInvokeStr(lib, "main"));
3433
3434 const char* kReloadScript =
3435 "const value = const Duration(seconds: 2);\n"
3436 "main() {\n"
3437 " return 'value=${value}';\n"
3438 "}\n";
3439
3440 lib = TestCase::ReloadTestScript(kReloadScript);
3441 EXPECT_VALID(lib);
3442 EXPECT_STREQ("value=0:00:02.000000", SimpleInvokeStr(lib, "main"));
3443}
3444
3445TEST_CASE(IsolateReload_RunNewFieldInitializers) {
3446 const char* late_tag = TestCase::LateTag();
3447 // clang-format off
3448 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
3449 "class Foo {\n"
3450 " int x = 4;\n"
3451 "}\n"
3452 "%s Foo value;\n"
3453 "main() {\n"
3454 " value = Foo();\n"
3455 " return value.x;\n"
3456 "}\n",
3457 late_tag),
3458 std::free);
3459 // clang-format on
3460
3461 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
3462 EXPECT_VALID(lib);
3463 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
3464
3465 // Add the field y.
3466 // clang-format off
3467 auto kReloadScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
3468 "class Foo {\n"
3469 " int x = 4;\n"
3470 " int y = 7;\n"
3471 "}\n"
3472 "%s Foo value;\n"
3473 "main() {\n"
3474 " return value.y;\n"
3475 "}\n",
3476 late_tag),
3477 std::free);
3478 // clang-format on
3479
3480 lib = TestCase::ReloadTestScript(kReloadScript.get());
3481 EXPECT_VALID(lib);
3482 // Verify that we ran field initializers on existing instances.
3483 EXPECT_EQ(7, SimpleInvoke(lib, "main"));
3484}
3485
3486TEST_CASE(IsolateReload_RunNewFieldInitializersReferenceStaticField) {
3487 const char* late_tag = TestCase::LateTag();
3488 // clang-format off
3489 auto kScript =
3490 Utils::CStringUniquePtr(OS::SCreate(nullptr,
3491 "int myInitialValue = 8 * 7;\n"
3492 "class Foo {\n"
3493 " int x = 4;\n"
3494 "}\n"
3495 "%s Foo value;\n"
3496 "main() {\n"
3497 " value = Foo();\n"
3498 " return value.x;\n"
3499 "}\n",
3500 late_tag),
3501 std::free);
3502 // clang-format on
3503
3504 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
3505 EXPECT_VALID(lib);
3506 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
3507
3508 // Add the field y.
3509 // clang-format off
3510 auto kReloadScript =
3511 Utils::CStringUniquePtr(OS::SCreate(nullptr,
3512 "int myInitialValue = 8 * 7;\n"
3513 "class Foo {\n"
3514 " int x = 4;\n"
3515 " int y = myInitialValue;\n"
3516 "}\n"
3517 "%s Foo value;\n"
3518 "main() {\n"
3519 " return value.y;\n"
3520 "}\n",
3521 late_tag),
3522 std::free);
3523 // clang-format on
3524
3525 lib = TestCase::ReloadTestScript(kReloadScript.get());
3526 EXPECT_VALID(lib);
3527 // Verify that we ran field initializers on existing instances.
3528 EXPECT_EQ(56, SimpleInvoke(lib, "main"));
3529}
3530
3531TEST_CASE(IsolateReload_RunNewFieldInitializersLazy) {
3532 const char* late_tag = TestCase::LateTag();
3533 // clang-format off
3534 auto kScript =
3535 Utils::CStringUniquePtr(OS::SCreate(nullptr,
3536 "int myInitialValue = 8 * 7;\n"
3537 "class Foo {\n"
3538 " int x = 4;\n"
3539 "}\n"
3540 "%s Foo value;\n"
3541 "%s Foo value1;\n"
3542 "main() {\n"
3543 " value = Foo();\n"
3544 " value1 = Foo();\n"
3545 " return value.x;\n"
3546 "}\n",
3547 late_tag, late_tag),
3548 std::free);
3549 // clang-format on
3550
3551 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
3552 EXPECT_VALID(lib);
3553 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
3554
3555 // Add the field y.
3556 // clang-format off
3557 auto kReloadScript = Utils::CStringUniquePtr(
3558 OS::SCreate(nullptr,
3559 "int myInitialValue = 8 * 7;\n"
3560 "class Foo {\n"
3561 " int x = 4;\n"
3562 " int y = myInitialValue++;\n"
3563 "}\n"
3564 "%s Foo value;\n"
3565 "%s Foo value1;\n"
3566 "main() {\n"
3567 " return '${myInitialValue} ${value.y} ${value1.y} "
3568 "${myInitialValue}';\n"
3569 "}\n",
3570 late_tag, late_tag),
3571 std::free);
3572 // clang-format on
3573
3574 lib = TestCase::ReloadTestScript(kReloadScript.get());
3575 EXPECT_VALID(lib);
3576 // Verify that field initializers ran lazily.
3577 EXPECT_STREQ("56 56 57 58", SimpleInvokeStr(lib, "main"));
3578}
3579
3580TEST_CASE(IsolateReload_RunNewFieldInitializersLazyConst) {
3581 const char* late_tag = TestCase::LateTag();
3582 // clang-format off
3583 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
3584 "class Foo {\n"
3585 " int x = 4;\n"
3586 "}\n"
3587 "%s Foo value;\n"
3588 "main() {\n"
3589 " value = Foo();\n"
3590 " return value.x;\n"
3591 "}\n",
3592 late_tag),
3593 std::free);
3594 // clang-format on
3595
3596 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
3597 EXPECT_VALID(lib);
3598 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
3599
3600 // Add the field y. Do not read it. Note field y does not get an initializer
3601 // function in the VM because the initializer is a literal, but we should not
3602 // eagerly initialize with the literal so that the behavior doesn't depend on
3603 // this optimization.
3604 // clang-format off
3605 auto kReloadScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
3606 "class Foo {\n"
3607 " int x = 4;\n"
3608 " int y = 5;\n"
3609 "}\n"
3610 "%s Foo value;\n"
3611 "main() {\n"
3612 " return 0;\n"
3613 "}\n",
3614 late_tag),
3615 std::free);
3616 // clang-format on
3617
3618 lib = TestCase::ReloadTestScript(kReloadScript.get());
3619 EXPECT_VALID(lib);
3620 EXPECT_EQ(0, SimpleInvoke(lib, "main"));
3621
3622 // Change y's initializer and check this new initializer is used.
3623 auto kReloadScript2 =
3624 Utils::CStringUniquePtr(OS::SCreate(nullptr,
3625 "class Foo {\n"
3626 " int x = 4;\n"
3627 " int y = 6;\n"
3628 "}\n"
3629 "%s Foo value;\n"
3630 "main() {\n"
3631 " return value.y;\n"
3632 "}\n",
3633 late_tag),
3634 std::free);
3635
3636 lib = TestCase::ReloadTestScript(kReloadScript2.get());
3637 EXPECT_VALID(lib);
3638 EXPECT_EQ(6, SimpleInvoke(lib, "main"));
3639}
3640
3641TEST_CASE(IsolateReload_RunNewFieldInitializersLazyTransitive) {
3642 const char* late_tag = TestCase::LateTag();
3643 // clang-format off
3644 auto kScript =
3645 Utils::CStringUniquePtr(OS::SCreate(nullptr,
3646 "int myInitialValue = 8 * 7;\n"
3647 "class Foo {\n"
3648 " int x = 4;\n"
3649 "}\n"
3650 "%s Foo value;\n"
3651 "%s Foo value1;\n"
3652 "main() {\n"
3653 " value = Foo();\n"
3654 " value1 = Foo();\n"
3655 " return value.x;\n"
3656 "}\n",
3657 late_tag, late_tag),
3658 std::free);
3659 // clang-format on
3660
3661 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
3662 EXPECT_VALID(lib);
3663 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
3664
3665 // Add the field y. Do not touch y.
3666 // clang-format off
3667 auto kReloadScript =
3668 Utils::CStringUniquePtr(OS::SCreate(nullptr,
3669 "int myInitialValue = 8 * 7;\n"
3670 "class Foo {\n"
3671 " int x = 4;\n"
3672 " int y = myInitialValue++;\n"
3673 "}\n"
3674 "%s Foo value;\n"
3675 "%s Foo value1;\n"
3676 "main() {\n"
3677 " return '${myInitialValue}';\n"
3678 "}\n",
3679 late_tag, late_tag),
3680 std::free);
3681 // clang-format on
3682
3683 lib = TestCase::ReloadTestScript(kReloadScript.get());
3684 EXPECT_VALID(lib);
3685 EXPECT_STREQ("56", SimpleInvokeStr(lib, "main"));
3686
3687 // Reload again. Field y's getter still needs to keep for initialization even
3688 // though it is no longer new.
3689 // clang-format off
3690 auto kReloadScript2 = Utils::CStringUniquePtr(
3691 OS::SCreate(nullptr,
3692 "int myInitialValue = 8 * 7;\n"
3693 "class Foo {\n"
3694 " int x = 4;\n"
3695 " int y = myInitialValue++;\n"
3696 "}\n"
3697 "%s Foo value;\n"
3698 "%s Foo value1;\n"
3699 "main() {\n"
3700 " return '${myInitialValue} ${value.y} ${value1.y} "
3701 "${myInitialValue}';\n"
3702 "}\n",
3703 late_tag, late_tag),
3704 std::free);
3705 // clang-format on
3706
3707 lib = TestCase::ReloadTestScript(kReloadScript2.get());
3708 EXPECT_VALID(lib);
3709 // Verify that field initializers ran lazily.
3710 EXPECT_STREQ("56 56 57 58", SimpleInvokeStr(lib, "main"));
3711}
3712
3713TEST_CASE(IsolateReload_RunNewFieldInitializersThrows) {
3714 const char* late_tag = TestCase::LateTag();
3715 // clang-format off
3716 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
3717 "class Foo {\n"
3718 " int x = 4;\n"
3719 "}\n"
3720 "%s Foo value;\n"
3721 "main() {\n"
3722 " value = Foo();\n"
3723 " return value.x;\n"
3724 "}\n",
3725 late_tag),
3726 std::free);
3727 // clang-format on
3728
3729 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
3730 EXPECT_VALID(lib);
3731 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
3732
3733 // Add the field y.
3734 // clang-format off
3735 auto kReloadScript =
3736 Utils::CStringUniquePtr(OS::SCreate(nullptr,
3737 "class Foo {\n"
3738 " int x = 4;\n"
3739 " int y = throw 'exception';\n"
3740 "}\n"
3741 "%s Foo value;\n"
3742 "main() {\n"
3743 " try {\n"
3744 " return value.y.toString();\n"
3745 " } catch (e) {\n"
3746 " return e.toString();\n"
3747 " }\n"
3748 "}\n",
3749 late_tag),
3750 std::free);
3751 // clang-format on
3752
3753 lib = TestCase::ReloadTestScript(kReloadScript.get());
3754 EXPECT_VALID(lib);
3755 // Verify that we ran field initializers on existing instances.
3756 EXPECT_STREQ("exception", SimpleInvokeStr(lib, "main"));
3757}
3758
3759TEST_CASE(IsolateReload_RunNewFieldInitializersCyclicInitialization) {
3760 const char* late_tag = TestCase::LateTag();
3761 // clang-format off
3762 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
3763 "class Foo {\n"
3764 " int x = 4;\n"
3765 "}\n"
3766 "%s Foo value;\n"
3767 "main() {\n"
3768 " value = Foo();\n"
3769 " return value.x;\n"
3770 "}\n",
3771 late_tag),
3772 std::free);
3773 // clang-format on
3774
3775 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
3776 EXPECT_VALID(lib);
3777 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
3778
3779 // Add the field y.
3780 // clang-format off
3781 auto kReloadScript =
3782 Utils::CStringUniquePtr(OS::SCreate(nullptr,
3783 "class Foo {\n"
3784 " int x = 4;\n"
3785 " int y = value.y;\n"
3786 "}\n"
3787 "%s Foo value;\n"
3788 "main() {\n"
3789 " try {\n"
3790 " return value.y.toString();\n"
3791 " } catch (e) {\n"
3792 " return e.toString();\n"
3793 " }\n"
3794 "}\n",
3795 late_tag),
3796 std::free);
3797 // clang-format on
3798 lib = TestCase::ReloadTestScript(kReloadScript.get());
3799 EXPECT_VALID(lib);
3800 EXPECT_STREQ("Stack Overflow", SimpleInvokeStr(lib, "main"));
3801}
3802
3803// When an initializer expression has a syntax error, we detect it at reload
3804// time.
3805TEST_CASE(IsolateReload_RunNewFieldInitializersSyntaxError) {
3806 const char* late_tag = TestCase::LateTag();
3807 // clang-format off
3808 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
3809 "class Foo {\n"
3810 " int x = 4;\n"
3811 "}\n"
3812 "%s Foo value;\n"
3813 "main() {\n"
3814 " value = Foo();\n"
3815 " return value.x;\n"
3816 "}\n",
3817 late_tag),
3818 std::free);
3819 // clang-format on
3820
3821 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
3822 EXPECT_VALID(lib);
3823 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
3824
3825 // Add the field y with a syntax error in the initializing expression.
3826 // clang-format off
3827 auto kReloadScript =
3828 Utils::CStringUniquePtr(OS::SCreate(nullptr,
3829 "class Foo {\n"
3830 " int x = 4;\n"
3831 " int y = ......;\n"
3832 "}\n"
3833 "%s Foo value;\n"
3834 "main() {\n"
3835 " return '${value.y == null}';"
3836 "}\n",
3837 late_tag),
3838 std::free);
3839 // clang-format on
3840
3841 // The reload fails because the initializing expression is parsed at
3842 // class finalization time.
3843 lib = TestCase::ReloadTestScript(kReloadScript.get());
3844 EXPECT_ERROR(lib, "...");
3845}
3846
3847// When an initializer expression has a syntax error, we detect it at reload
3848// time.
3849TEST_CASE(IsolateReload_RunNewFieldInitializersSyntaxError2) {
3850 const char* late_tag = TestCase::LateTag();
3851 // clang-format off
3852 auto kScript = Utils::CStringUniquePtr(
3853 OS::SCreate(nullptr,
3854 "class Foo {\n"
3855 " Foo() { /* default constructor */ }\n"
3856 " int x = 4;\n"
3857 "}\n"
3858 "%s Foo value;\n"
3859 "main() {\n"
3860 " value = Foo();\n"
3861 " return value.x;\n"
3862 "}\n",
3863 late_tag),
3864 std::free);
3865 // clang-format on
3866
3867 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
3868 EXPECT_VALID(lib);
3869 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
3870
3871 // Add the field y with a syntax error in the initializing expression.
3872 // clang-format off
3873 auto kReloadScript = Utils::CStringUniquePtr(
3874 OS::SCreate(nullptr,
3875 "class Foo {\n"
3876 " Foo() { /* default constructor */ }\n"
3877 " int x = 4;\n"
3878 " int y = ......;\n"
3879 "}\n"
3880 "%s Foo value;\n"
3881 "main() {\n"
3882 " return '${value.y == null}';"
3883 "}\n",
3884 late_tag),
3885 std::free);
3886 // clang-format on
3887
3888 // The reload fails because the initializing expression is parsed at
3889 // class finalization time.
3890 lib = TestCase::ReloadTestScript(kReloadScript.get());
3891 EXPECT_ERROR(lib, "...");
3892}
3893
3894// When an initializer expression has a syntax error, we detect it at reload
3895// time.
3896TEST_CASE(IsolateReload_RunNewFieldInitializersSyntaxError3) {
3897 const char* late_tag = TestCase::LateTag();
3898 // clang-format off
3899 auto kScript = Utils::CStringUniquePtr(
3900 OS::SCreate(nullptr,
3901 "class Foo {\n"
3902 " Foo() { /* default constructor */ }\n"
3903 " int x = 4;\n"
3904 "}\n"
3905 "%s Foo value;\n"
3906 "main() {\n"
3907 " value = Foo();\n"
3908 " return value.x;\n"
3909 "}\n",
3910 late_tag),
3911 std::free);
3912 // clang-format on
3913
3914 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
3915 EXPECT_VALID(lib);
3916 EXPECT_EQ(4, SimpleInvoke(lib, "main"));
3917
3918 // Add the field y with a syntax error in the initializing expression.
3919 // clang-format off
3920 auto kReloadScript = Utils::CStringUniquePtr(
3921 OS::SCreate(nullptr,
3922 "class Foo {\n"
3923 " Foo() { /* default constructor */ }\n"
3924 " int x = 4;\n"
3925 " int y = ......\n"
3926 "}\n"
3927 "%s Foo value;\n"
3928 "main() {\n"
3929 " return '${value.y == null}';"
3930 "}\n",
3931 late_tag),
3932 std::free);
3933 // clang-format on
3934
3935 // The reload fails because the initializing expression is parsed at
3936 // class finalization time.
3937 lib = TestCase::ReloadTestScript(kReloadScript.get());
3938 EXPECT_ERROR(lib, "......");
3939}
3940
3941TEST_CASE(IsolateReload_RunNewFieldInitializersSuperClass) {
3942 const char* late_tag = TestCase::LateTag();
3943 // clang-format off
3944 auto kScript =
3945 Utils::CStringUniquePtr(OS::SCreate(nullptr,
3946 "class Super {\n"
3947 " static var foo = 'right';\n"
3948 "}\n"
3949 "class Foo extends Super {\n"
3950 " static var foo = 'wrong';\n"
3951 "}\n"
3952 "%s Foo value;\n"
3953 "main() {\n"
3954 " Super.foo;\n"
3955 " Foo.foo;\n"
3956 " value = Foo();\n"
3957 " return 0;\n"
3958 "}\n",
3959 late_tag),
3960 std::free);
3961 // clang-format on
3962
3963 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
3964 EXPECT_VALID(lib);
3965 EXPECT_EQ(0, SimpleInvoke(lib, "main"));
3966
3967 // clang-format on
3968 auto kReloadScript =
3969 Utils::CStringUniquePtr(OS::SCreate(nullptr,
3970 "class Super {\n"
3971 " static var foo = 'right';\n"
3972 " var newField = foo;\n"
3973 "}\n"
3974 "class Foo extends Super {\n"
3975 " static var foo = 'wrong';\n"
3976 "}\n"
3977 "%s Foo value;\n"
3978 "main() {\n"
3979 " return value.newField;\n"
3980 "}\n",
3981 late_tag),
3982 std::free);
3983 // clang-format off
3984
3985 lib = TestCase::ReloadTestScript(kReloadScript.get());
3986 EXPECT_VALID(lib);
3987 // Verify that we ran field initializers on existing instances in the
3988 // correct scope.
3989 const char* actual = SimpleInvokeStr(lib, "main");
3990 EXPECT(actual != nullptr);
3991 if (actual != nullptr) {
3992 EXPECT_STREQ("right", actual);
3993 }
3994}
3995
3996TEST_CASE(IsolateReload_RunNewFieldInitializersWithConsts) {
3997 const char* late_tag = TestCase::LateTag();
3998 // clang-format off
3999 auto kScript =
4000 Utils::CStringUniquePtr(OS::SCreate(nullptr,
4001 "class C {\n"
4002 " final x;\n"
4003 " const C(this.x);\n"
4004 "}\n"
4005 "var a = const C(const C(1));\n"
4006 "var b = const C(const C(2));\n"
4007 "var c = const C(const C(3));\n"
4008 "var d = const C(const C(4));\n"
4009 "class Foo {\n"
4010 "}\n"
4011 "%s Foo value;\n"
4012 "main() {\n"
4013 " value = Foo();\n"
4014 " a; b; c; d;\n"
4015 " return 'Okay';\n"
4016 "}\n",
4017 late_tag),
4018 std::free);
4019 // clang-format on
4020
4021 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), nullptr);
4022 EXPECT_VALID(lib);
4023 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
4024
4025 // clang-format off
4026 auto kReloadScript = Utils::CStringUniquePtr(
4027 OS::SCreate(
4028 nullptr,
4029 "class C {\n"
4030 " final x;\n"
4031 " const C(this.x);\n"
4032 "}\n"
4033 "var a = const C(const C(1));\n"
4034 "var b = const C(const C(2));\n"
4035 "var c = const C(const C(3));\n"
4036 "var d = const C(const C(4));\n"
4037 "class Foo {\n"
4038 " var d = const C(const C(4));\n"
4039 " var c = const C(const C(3));\n"
4040 " var b = const C(const C(2));\n"
4041 " var a = const C(const C(1));\n"
4042 "}\n"
4043 "%s Foo value;\n"
4044 "main() {\n"
4045 " return '${identical(a, value.a)} ${identical(b, value.b)}'"
4046 " ' ${identical(c, value.c)} ${identical(d, value.d)}';\n"
4047 "}\n",
4048 late_tag),
4049 std::free);
4050 // clang-format on
4051 lib = TestCase::ReloadTestScript(kReloadScript.get());
4052 EXPECT_VALID(lib);
4053 // Verify that we ran field initializers on existing instances and the const
4054 // expressions were properly canonicalized.
4055 EXPECT_STREQ("true true true true", SimpleInvokeStr(lib, "main"));
4056}
4057
4058TEST_CASE(IsolateReload_RunNewFieldInitializersWithGenerics) {
4059 const char* nullable_tag = TestCase::NullableTag();
4060 const char* late_tag = TestCase::LateTag();
4061 // clang-format off
4062 auto kScript =
4063 Utils::CStringUniquePtr(OS::SCreate(nullptr,
4064 "class Foo<T> {\n"
4065 " T%s x;\n"
4066 "}\n"
4067 "%s Foo value1;\n"
4068 "%s Foo value2;\n"
4069 "main() {\n"
4070 " value1 = Foo<String>();\n"
4071 " value2 = Foo<int>();\n"
4072 " return 'Okay';\n"
4073 "}\n",
4074 nullable_tag, late_tag, late_tag),
4075 std::free);
4076 // clang-format on
4077
4078 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
4079 EXPECT_VALID(lib);
4080 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
4081
4082 // clang-format off
4083 auto kReloadScript = Utils::CStringUniquePtr(
4084 OS::SCreate(nullptr,
4085 "class Foo<T> {\n"
4086 " T%s x;\n"
4087 " List<T> y = List<T>.empty();"
4088 " dynamic z = <T,T>{};"
4089 "}\n"
4090 "%s Foo value1;\n"
4091 "%s Foo value2;\n"
4092 "main() {\n"
4093 " return '${value1.y.runtimeType} ${value1.z.runtimeType}'"
4094 " ' ${value2.y.runtimeType} ${value2.z.runtimeType}';\n"
4095 "}\n",
4096 nullable_tag, late_tag, late_tag),
4097 std::free);
4098 // clang-format on
4099
4100 lib = TestCase::ReloadTestScript(kReloadScript.get());
4101 EXPECT_VALID(lib);
4102 // Verify that we ran field initializers on existing instances and
4103 // correct type arguments were used.
4104 EXPECT_STREQ(
4105 "List<String> _InternalLinkedHashMap<String, String> List<int> "
4106 "_InternalLinkedHashMap<int, int>",
4107 SimpleInvokeStr(lib, "main"));
4108}
4109
4110TEST_CASE(IsolateReload_AddNewStaticField) {
4111 const char* kScript =
4112 "class C {\n"
4113 "}\n"
4114 "main() {\n"
4115 " return 'Okay';\n"
4116 "}\n";
4117
4118 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
4119 EXPECT_VALID(lib);
4120 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
4121
4122 const char* kReloadScript =
4123 "class C {\n"
4124 " static var x = 42;\n"
4125 "}\n"
4126 "main() {\n"
4127 " return '${C.x}';\n"
4128 "}\n";
4129
4130 lib = TestCase::ReloadTestScript(kReloadScript);
4131 EXPECT_VALID(lib);
4132 EXPECT_STREQ("42", SimpleInvokeStr(lib, "main"));
4133}
4134
4135TEST_CASE(IsolateReload_StaticFieldInitialValueDoesnotChange) {
4136 const char* kScript =
4137 "class C {\n"
4138 " static var x = 42;\n"
4139 "}\n"
4140 "main() {\n"
4141 " return '${C.x}';\n"
4142 "}\n";
4143
4144 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
4145 EXPECT_VALID(lib);
4146 EXPECT_STREQ("42", SimpleInvokeStr(lib, "main"));
4147
4148 const char* kReloadScript =
4149 "class C {\n"
4150 " static var x = 13;\n"
4151 "}\n"
4152 "main() {\n"
4153 " return '${C.x}';\n"
4154 "}\n";
4155
4156 lib = TestCase::ReloadTestScript(kReloadScript);
4157 EXPECT_VALID(lib);
4158 // Newly loaded field maintained old static value
4159 EXPECT_STREQ("42", SimpleInvokeStr(lib, "main"));
4160}
4161
4162class FindNoInstancesOfClass : public FindObjectVisitor {
4163 public:
4164 explicit FindNoInstancesOfClass(intptr_t cid) : cid_(cid) {
4165#if defined(DEBUG)
4166 EXPECT_GT(Thread::Current()->no_safepoint_scope_depth(), 0);
4167#endif
4168 }
4169 virtual ~FindNoInstancesOfClass() {}
4170
4171 virtual bool FindObject(ObjectPtr obj) const {
4172 return obj->GetClassId() == cid_;
4173 }
4174
4175 private:
4176 intptr_t cid_;
4177};
4178
4179TEST_CASE(IsolateReload_DeleteStaticField) {
4180 const char* kScript =
4181 "class C {\n"
4182 "}\n"
4183 "class Foo {\n"
4184 "static var x = C();\n"
4185 "}\n"
4186 "main() {\n"
4187 " return Foo.x;\n"
4188 "}\n";
4189
4190 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
4191 EXPECT_VALID(lib);
4192 intptr_t cid = 1118;
4193 {
4194 Dart_EnterScope();
4195 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
4196 EXPECT_VALID(result);
4197 {
4198 TransitionNativeToVM transition(thread);
4199 cid = Api::ClassId(result);
4200 }
4201 Dart_ExitScope();
4202 }
4203
4204 const char* kReloadScript =
4205 "class C {\n"
4206 "}\n"
4207 "class Foo {\n"
4208 "}\n"
4209 "main() {\n"
4210 " return '${Foo()}';\n"
4211 "}\n";
4212
4213 lib = TestCase::ReloadTestScript(kReloadScript);
4214 EXPECT_VALID(lib);
4215 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
4216 EXPECT_VALID(result);
4217 {
4218 TransitionNativeToVM transition(thread);
4219 GCTestHelper::CollectAllGarbage();
4220
4221 {
4222 HeapIterationScope iteration(thread);
4223 NoSafepointScope no_safepoint;
4224 FindNoInstancesOfClass find_only(cid);
4225 Isolate* isolate = Isolate::Current();
4226 Heap* heap = isolate->heap();
4227 // We still expect to find references to static field values
4228 // because they are not deleted after hot reload.
4229 EXPECT_NE(heap->FindObject(&find_only), Object::null());
4230 }
4231 }
4232}
4233
4234TEST_CASE(IsolateReload_ExistingFieldChangesType) {
4235 const char* late_tag = TestCase::LateTag();
4236 // clang-format off
4237 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr,
4238 R"(
4239 class Foo {
4240 int x = 42;
4241 }
4242 %s Foo value;
4243 main() {
4244 value = Foo();
4245 return 'Okay';
4246 }
4247 )",
4248 late_tag), std::free);
4249 // clang-format on
4250
4251 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
4252 EXPECT_VALID(lib);
4253 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
4254
4255 // clang-format off
4256 auto kReloadScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
4257 class Foo {
4258 double x = 42.0;
4259 }
4260 %s Foo value;
4261 main() {
4262 try {
4263 return value.x.toString();
4264 } catch (e) {
4265 return e.toString();
4266 }
4267 }
4268 )",
4269 late_tag), std::free);
4270 // clang-format on
4271
4272 lib = TestCase::ReloadTestScript(kReloadScript.get());
4273 EXPECT_VALID(lib);
4274 EXPECT_STREQ(
4275 "type 'int' is not a subtype of type 'double' of 'function result'",
4276 SimpleInvokeStr(lib, "main"));
4277}
4278
4279TEST_CASE(IsolateReload_ExistingStaticFieldChangesType) {
4280 const char* kScript = R"(
4281 int value = init();
4282 init() => 42;
4283 main() {
4284 return value.toString();
4285 }
4286 )";
4287
4288 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
4289 EXPECT_VALID(lib);
4290 EXPECT_STREQ("42", SimpleInvokeStr(lib, "main"));
4291
4292 const char* kReloadScript = R"(
4293 double value = init();
4294 init() => 42.0;
4295 main() {
4296 try {
4297 return value.toString();
4298 } catch (e) {
4299 return e.toString();
4300 }
4301 }
4302 )";
4303
4304 lib = TestCase::ReloadTestScript(kReloadScript);
4305 EXPECT_VALID(lib);
4306 EXPECT_STREQ(
4307 "type 'int' is not a subtype of type 'double' of 'function result'",
4308 SimpleInvokeStr(lib, "main"));
4309}
4310
4311TEST_CASE(IsolateReload_ExistingFieldChangesTypeIndirect) {
4312 const char* late_tag = TestCase::LateTag();
4313 // clang-format off
4314 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
4315 class A {}
4316 class B extends A {}
4317 class Foo {
4318 A x;
4319 Foo(this.x);
4320 }
4321 %s Foo value;
4322 main() {
4323 value = Foo(B());
4324 return 'Okay';
4325 }
4326 )", late_tag), std::free);
4327 // clang-format on
4328
4329 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
4330 EXPECT_VALID(lib);
4331 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
4332
4333 // B is no longer a subtype of A.
4334 // clang-format off
4335 auto kReloadScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
4336 class A {}
4337 class B {}
4338 class Foo {
4339 A x;
4340 Foo(this.x);
4341 }
4342 %s Foo value;
4343 main() {
4344 try {
4345 return value.x.toString();
4346 } catch (e) {
4347 return e.toString();
4348 }
4349 }
4350 )", late_tag), std::free);
4351 // clang-format on
4352
4353 lib = TestCase::ReloadTestScript(kReloadScript.get());
4354 EXPECT_VALID(lib);
4355 EXPECT_STREQ("type 'B' is not a subtype of type 'A' of 'function result'",
4356 SimpleInvokeStr(lib, "main"));
4357}
4358
4359TEST_CASE(IsolateReload_ExistingStaticFieldChangesTypeIndirect) {
4360 const char* kScript = R"(
4361 class A {}
4362 class B extends A {}
4363 A value = init();
4364 init() => new B();
4365 main() {
4366 return value.toString();
4367 }
4368 )";
4369
4370 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
4371 EXPECT_VALID(lib);
4372 EXPECT_STREQ("Instance of 'B'", SimpleInvokeStr(lib, "main"));
4373
4374 // B is no longer a subtype of A.
4375 const char* kReloadScript = R"(
4376 class A {}
4377 class B {}
4378 A value = init();
4379 init() => new A();
4380 main() {
4381 try {
4382 return value.toString();
4383 } catch (e) {
4384 return e.toString();
4385 }
4386 }
4387 )";
4388
4389 lib = TestCase::ReloadTestScript(kReloadScript);
4390 EXPECT_VALID(lib);
4391 EXPECT_STREQ("type 'B' is not a subtype of type 'A' of 'function result'",
4392 SimpleInvokeStr(lib, "main"));
4393}
4394
4395TEST_CASE(IsolateReload_ExistingFieldChangesTypeIndirectGeneric) {
4396 const char* late_tag = TestCase::LateTag();
4397 // clang-format off
4398 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
4399 class A {}
4400 class B extends A {}
4401 class Foo {
4402 List<A> x;
4403 Foo(this.x);
4404 }
4405 %s Foo value;
4406 main() {
4407 value = Foo(List<B>.empty());
4408 return 'Okay';
4409 }
4410 )", late_tag), std::free);
4411 // clang-format on
4412
4413 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
4414 EXPECT_VALID(lib);
4415 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
4416
4417 // B is no longer a subtype of A.
4418 // clang-format off
4419 auto kReloadScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
4420 class A {}
4421 class B {}
4422 class Foo {
4423 List<A> x;
4424 Foo(this.x);
4425 }
4426 %s Foo value;
4427 main() {
4428 try {
4429 return value.x.toString();
4430 } catch (e) {
4431 return e.toString();
4432 }
4433 }
4434 )", late_tag), std::free);
4435 // clang-format on
4436
4437 lib = TestCase::ReloadTestScript(kReloadScript.get());
4438 EXPECT_VALID(lib);
4439 EXPECT_STREQ(
4440 "type 'List<B>' is not a subtype of type 'List<A>' of 'function result'",
4441 SimpleInvokeStr(lib, "main"));
4442}
4443
4444TEST_CASE(IsolateReload_ExistingStaticFieldChangesTypeIndirectGeneric) {
4445 const char* kScript = R"(
4446 class A {}
4447 class B extends A {}
4448 List<A> value = init();
4449 init() => List<B>.empty();
4450 main() {
4451 return value.toString();
4452 }
4453 )";
4454
4455 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
4456 EXPECT_VALID(lib);
4457 EXPECT_STREQ("[]", SimpleInvokeStr(lib, "main"));
4458
4459 // B is no longer a subtype of A.
4460 const char* kReloadScript = R"(
4461 class A {}
4462 class B {}
4463 List<A> value = init();
4464 init() => List<A>.empty();
4465 main() {
4466 try {
4467 return value.toString();
4468 } catch (e) {
4469 return e.toString();
4470 }
4471 }
4472 )";
4473
4474 lib = TestCase::ReloadTestScript(kReloadScript);
4475 EXPECT_VALID(lib);
4476 EXPECT_STREQ(
4477 "type 'List<B>' is not a subtype of type 'List<A>' of 'function result'",
4478 SimpleInvokeStr(lib, "main"));
4479}
4480
4481TEST_CASE(IsolateReload_ExistingFieldChangesTypeIndirectFunction) {
4482 const char* late_tag = TestCase::LateTag();
4483 // clang-format off
4484 auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
4485 class A {}
4486 class B extends A {}
4487 typedef bool Predicate(B b);
4488 class Foo {
4489 Predicate x;
4490 Foo(this.x);
4491 }
4492 %s Foo value;
4493 main() {
4494 value = Foo((A a) => true);
4495 return 'Okay';
4496 }
4497 )", late_tag), std::free);
4498 // clang-format on
4499
4500 Dart_Handle lib = TestCase::LoadTestScript(kScript.get(), NULL);
4501 EXPECT_VALID(lib);
4502 EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
4503
4504 // B is no longer a subtype of A.
4505 // clang-format off
4506 auto kReloadScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
4507 class A {}
4508 class B {}
4509 typedef bool Predicate(B b);
4510 class Foo {
4511 Predicate x;
4512 Foo(this.x);
4513 }
4514 %s Foo value;
4515 main() {
4516 try {
4517 return value.x.toString();
4518 } catch (e) {
4519 return e.toString();
4520 }
4521 }
4522 )", late_tag), std::free);
4523 // clang-format on
4524
4525 lib = TestCase::ReloadTestScript(kReloadScript.get());
4526 EXPECT_VALID(lib);
4527 EXPECT_STREQ(
4528 "type '(A) => bool' is not a subtype of type '(B) => bool' of 'function "
4529 "result'",
4530 SimpleInvokeStr(lib, "main"));
4531}
4532
4533TEST_CASE(IsolateReload_ExistingStaticFieldChangesTypeIndirectFunction) {
4534 const char* kScript = R"(
4535 class A {}
4536 class B extends A {}
4537 typedef bool Predicate(B b);
4538 Predicate value = init();
4539 init() => (A a) => true;
4540 main() {
4541 return value.toString();
4542 }
4543 )";
4544
4545 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
4546 EXPECT_VALID(lib);
4547 EXPECT_STREQ("Closure: (A) => bool", SimpleInvokeStr(lib, "main"));
4548
4549 // B is no longer a subtype of A.
4550 const char* kReloadScript = R"(
4551 class A {}
4552 class B {}
4553 typedef bool Predicate(B b);
4554 Predicate value = init();
4555 init() => (B a) => true;
4556 main() {
4557 try {
4558 return value.toString();
4559 } catch (e) {
4560 return e.toString();
4561 }
4562 }
4563 )";
4564
4565 lib = TestCase::ReloadTestScript(kReloadScript);
4566 EXPECT_VALID(lib);
4567 EXPECT_STREQ(
4568 "type '(A) => bool' is not a subtype of type '(B) => bool' of 'function "
4569 "result'",
4570 SimpleInvokeStr(lib, "main"));
4571}
4572
4573TEST_CASE(IsolateReload_TypedefToNotTypedef) {
4574 const char* kScript =
4575 "typedef bool Predicate(dynamic x);\n"
4576 "main() {\n"
4577 " return (42 is Predicate).toString();\n"
4578 "}\n";
4579
4580 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
4581 EXPECT_VALID(lib);
4582 EXPECT_STREQ("false", SimpleInvokeStr(lib, "main"));
4583
4584 const char* kReloadScript =
4585 "class Predicate {\n"
4586 " bool call(dynamic x) { return false; }\n"
4587 "}\n"
4588 "main() {\n"
4589 " return (42 is Predicate).toString();\n"
4590 "}\n";
4591
4592 Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
4593 EXPECT_ERROR(result,
4594 "Typedef class cannot be redefined to be a non-typedef class");
4595}
4596
4597TEST_CASE(IsolateReload_NotTypedefToTypedef) {
4598 const char* kScript =
4599 "class Predicate {\n"
4600 " bool call(dynamic x) { return false; }\n"
4601 "}\n"
4602 "main() {\n"
4603 " return (42 is Predicate).toString();\n"
4604 "}\n";
4605
4606 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
4607 EXPECT_VALID(lib);
4608 EXPECT_STREQ("false", SimpleInvokeStr(lib, "main"));
4609
4610 const char* kReloadScript =
4611 "typedef bool Predicate(dynamic x);\n"
4612 "main() {\n"
4613 " return (42 is Predicate).toString();\n"
4614 "}\n";
4615
4616 Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
4617 EXPECT_ERROR(result, "Class cannot be redefined to be a typedef class");
4618}
4619
4620TEST_CASE(IsolateReload_TypedefAddParameter) {
4621 const char* kScript =
4622 "typedef bool Predicate(dynamic x);\n"
4623 "main() {\n"
4624 " bool foo(x) => true;\n"
4625 " return (foo is Predicate).toString();\n"
4626 "}\n";
4627
4628 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
4629 EXPECT_VALID(lib);
4630 EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
4631
4632 const char* kReloadScript =
4633 "typedef bool Predicate(dynamic x, dynamic y);\n"
4634 "main() {\n"
4635 " bool foo(x) => true;\n"
4636 " return (foo is Predicate).toString();\n"
4637 "}\n";
4638
4639 Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
4640 EXPECT_VALID(result);
4641 EXPECT_STREQ("false", SimpleInvokeStr(lib, "main"));
4642}
4643
4644TEST_CASE(IsolateReload_PatchStaticInitializerWithClosure) {
4645 const char* kScript =
4646 "dynamic field = (a) => 'a$a';\n"
4647 "main() {\n"
4648 " dynamic f = field;\n"
4649 " return f('b');\n"
4650 "}\n";
4651
4652 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
4653 EXPECT_VALID(lib);
4654 EXPECT_STREQ("ab", SimpleInvokeStr(lib, "main"));
4655
4656 const char* kReloadScript =
4657 "extraFunction() => 'Just here to change kernel offsets';\n"
4658 "dynamic field = (_, __) => 'Not executed';\n"
4659 "main() {\n"
4660 " dynamic f = field;\n"
4661 " return f('c');\n"
4662 "}\n";
4663
4664 lib = TestCase::ReloadTestScript(kReloadScript);
4665 EXPECT_VALID(lib);
4666 EXPECT_STREQ("ac", SimpleInvokeStr(lib, "main"));
4667}
4668
4669TEST_CASE(IsolateReload_StaticTargetArityChange) {
4670 const char* kScript = R"(
4671 class A {
4672 final x;
4673 final y;
4674 const A(this.x, this.y);
4675 }
4676
4677 dynamic closure;
4678
4679 main() {
4680 closure = () => A(1, 2);
4681 return "okay";
4682 }
4683 )";
4684
4685 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
4686 EXPECT_VALID(lib);
4687 EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
4688
4689 const char* kReloadScript = R"(
4690 class A {
4691 final x;
4692 const A(this.x);
4693 }
4694
4695 dynamic closure;
4696
4697 main() {
4698 // Call the old closure, which will try to call A(1, 2).
4699 closure();
4700
4701 return "okay";
4702 }
4703 )";
4704
4705 lib = TestCase::ReloadTestScript(kReloadScript);
4706 EXPECT_VALID(lib);
4707 EXPECT_ERROR(SimpleInvokeError(lib, "main"),
4708 "Unhandled exception:\n"
4709 "NoSuchMethodError: No constructor 'A.' "
4710 "with matching arguments declared in class 'A'.");
4711}
4712
4713#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
4714
4715} // namespace dart
4716