1 | // Copyright (c) 2012, 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 "vm/unit_test.h" |
6 | |
7 | #include <stdio.h> |
8 | |
9 | #include "bin/builtin.h" |
10 | #include "bin/dartutils.h" |
11 | #include "bin/isolate_data.h" |
12 | |
13 | #include "platform/globals.h" |
14 | |
15 | #include "vm/compiler/assembler/assembler.h" |
16 | #include "vm/compiler/assembler/disassembler.h" |
17 | #include "vm/compiler/jit/compiler.h" |
18 | #include "vm/dart_api_impl.h" |
19 | #include "vm/isolate_reload.h" |
20 | #include "vm/kernel_isolate.h" |
21 | #include "vm/parser.h" |
22 | #include "vm/symbols.h" |
23 | #include "vm/thread.h" |
24 | #include "vm/virtual_memory.h" |
25 | |
26 | using dart::bin::Builtin; |
27 | using dart::bin::DartUtils; |
28 | |
29 | extern "C" { |
30 | extern const uint8_t kPlatformStrongDill[]; |
31 | extern intptr_t kPlatformStrongDillSize; |
32 | } |
33 | |
34 | namespace dart { |
35 | |
36 | DECLARE_FLAG(bool, gc_during_reload); |
37 | DECLARE_FLAG(bool, force_evacuation); |
38 | |
39 | const uint8_t* platform_strong_dill = kPlatformStrongDill; |
40 | const intptr_t platform_strong_dill_size = kPlatformStrongDillSize; |
41 | |
42 | const uint8_t* TesterState::vm_snapshot_data = NULL; |
43 | Dart_IsolateGroupCreateCallback TesterState::create_callback = NULL; |
44 | Dart_IsolateShutdownCallback TesterState::shutdown_callback = NULL; |
45 | Dart_IsolateGroupCleanupCallback TesterState::group_cleanup_callback = nullptr; |
46 | const char** TesterState::argv = NULL; |
47 | int TesterState::argc = 0; |
48 | |
49 | void KernelBufferList::AddBufferToList(const uint8_t* kernel_buffer) { |
50 | next_ = new KernelBufferList(kernel_buffer_, next_); |
51 | kernel_buffer_ = kernel_buffer; |
52 | } |
53 | |
54 | TestCaseBase* TestCaseBase::first_ = NULL; |
55 | TestCaseBase* TestCaseBase::tail_ = NULL; |
56 | KernelBufferList* TestCaseBase::current_kernel_buffers_ = NULL; |
57 | |
58 | TestCaseBase::TestCaseBase(const char* name, const char* expectation) |
59 | : raw_test_(false), |
60 | next_(NULL), |
61 | name_(name), |
62 | expectation_(strlen(expectation) > 0 ? expectation : "Pass" ) { |
63 | if (first_ == NULL) { |
64 | first_ = this; |
65 | } else { |
66 | tail_->next_ = this; |
67 | } |
68 | tail_ = this; |
69 | } |
70 | |
71 | void TestCaseBase::RunAllRaw() { |
72 | TestCaseBase* test = first_; |
73 | while (test != NULL) { |
74 | if (test->raw_test_) { |
75 | test->RunTest(); |
76 | CleanupState(); |
77 | } |
78 | test = test->next_; |
79 | } |
80 | } |
81 | |
82 | void TestCaseBase::RunAll() { |
83 | TestCaseBase* test = first_; |
84 | while (test != NULL) { |
85 | if (!test->raw_test_) { |
86 | test->RunTest(); |
87 | CleanupState(); |
88 | } |
89 | test = test->next_; |
90 | } |
91 | } |
92 | |
93 | void TestCaseBase::CleanupState() { |
94 | if (current_kernel_buffers_ != NULL) { |
95 | delete current_kernel_buffers_; |
96 | current_kernel_buffers_ = NULL; |
97 | } |
98 | } |
99 | |
100 | void TestCaseBase::AddToKernelBuffers(const uint8_t* kernel_buffer) { |
101 | ASSERT(kernel_buffer != NULL); |
102 | if (current_kernel_buffers_ == NULL) { |
103 | current_kernel_buffers_ = new KernelBufferList(kernel_buffer); |
104 | } else { |
105 | current_kernel_buffers_->AddBufferToList(kernel_buffer); |
106 | } |
107 | } |
108 | |
109 | Dart_Isolate TestCase::CreateIsolate(const uint8_t* data_buffer, |
110 | intptr_t len, |
111 | const uint8_t* instr_buffer, |
112 | const char* name, |
113 | void* group_data, |
114 | void* isolate_data) { |
115 | char* err; |
116 | Dart_IsolateFlags api_flags; |
117 | Isolate::FlagsInitialize(&api_flags); |
118 | api_flags.null_safety = (FLAG_sound_null_safety == kNullSafetyOptionStrong); |
119 | Dart_Isolate isolate = NULL; |
120 | if (len == 0) { |
121 | isolate = Dart_CreateIsolateGroup( |
122 | /*script_uri=*/name, /*name=*/name, data_buffer, instr_buffer, |
123 | &api_flags, group_data, isolate_data, &err); |
124 | } else { |
125 | isolate = Dart_CreateIsolateGroupFromKernel(/*script_uri=*/name, |
126 | /*name=*/name, data_buffer, len, |
127 | &api_flags, group_data, |
128 | isolate_data, &err); |
129 | } |
130 | if (isolate == NULL) { |
131 | OS::PrintErr("Creation of isolate failed '%s'\n" , err); |
132 | free(err); |
133 | } |
134 | |
135 | EXPECT(isolate != NULL); |
136 | return isolate; |
137 | } |
138 | |
139 | Dart_Isolate TestCase::CreateTestIsolate(const char* name, |
140 | void* group_data, |
141 | void* isolate_data) { |
142 | return CreateIsolate(bin::core_isolate_snapshot_data, |
143 | 0 /* Snapshots have length encoded within them. */, |
144 | bin::core_isolate_snapshot_instructions, name, |
145 | group_data, isolate_data); |
146 | } |
147 | |
148 | void SetupCoreLibrariesForUnitTest() { |
149 | TransitionVMToNative transition(Thread::Current()); |
150 | |
151 | Dart_EnterScope(); |
152 | bool ok = bin::DartUtils::SetOriginalWorkingDirectory(); |
153 | RELEASE_ASSERT(ok); |
154 | Dart_Handle result = bin::DartUtils::PrepareForScriptLoading( |
155 | /*is_service_isolate=*/false, |
156 | /*trace_loading=*/false); |
157 | Dart_ExitScope(); |
158 | |
159 | RELEASE_ASSERT(!Dart_IsError(result)); |
160 | } |
161 | |
162 | Dart_Isolate TestCase::CreateTestIsolateInGroup(const char* name, |
163 | Dart_Isolate parent, |
164 | void* group_data, |
165 | void* isolate_data) { |
166 | char* error; |
167 | #if defined(DART_PRECOMPILED_RUNTIME) |
168 | Isolate* result = CreateWithinExistingIsolateGroupAOT( |
169 | reinterpret_cast<Isolate*>(parent)->group(), name, &error); |
170 | #else |
171 | Isolate* result = CreateWithinExistingIsolateGroup( |
172 | reinterpret_cast<Isolate*>(parent)->group(), name, &error); |
173 | #endif |
174 | if (error != nullptr) { |
175 | OS::PrintErr("CreateTestIsolateInGroup failed: %s\n" , error); |
176 | free(error); |
177 | } |
178 | EXPECT(result != nullptr); |
179 | return Api::CastIsolate(result); |
180 | } |
181 | |
182 | struct TestLibEntry { |
183 | const char* url; |
184 | const char* source; |
185 | }; |
186 | |
187 | static MallocGrowableArray<TestLibEntry>* test_libs_ = NULL; |
188 | |
189 | const char* TestCase::url() { |
190 | return RESOLVED_USER_TEST_URI; |
191 | } |
192 | |
193 | void TestCase::AddTestLib(const char* url, const char* source) { |
194 | if (test_libs_ == NULL) { |
195 | test_libs_ = new MallocGrowableArray<TestLibEntry>(); |
196 | } |
197 | // If the test lib is already added, replace the source. |
198 | for (intptr_t i = 0; i < test_libs_->length(); i++) { |
199 | if (strcmp(url, (*test_libs_)[i].url) == 0) { |
200 | (*test_libs_)[i].source = source; |
201 | return; |
202 | } |
203 | } |
204 | TestLibEntry entry; |
205 | entry.url = url; |
206 | entry.source = source; |
207 | test_libs_->Add(entry); |
208 | } |
209 | |
210 | const char* TestCase::GetTestLib(const char* url) { |
211 | if (test_libs_ == NULL) { |
212 | return NULL; |
213 | } |
214 | for (intptr_t i = 0; i < test_libs_->length(); i++) { |
215 | if (strcmp(url, (*test_libs_)[i].url) == 0) { |
216 | return (*test_libs_)[i].source; |
217 | } |
218 | } |
219 | return NULL; |
220 | } |
221 | |
222 | bool TestCase::IsNNBD() { |
223 | return KernelIsolate::GetExperimentalFlag("non-nullable" ); |
224 | } |
225 | |
226 | #ifndef PRODUCT |
227 | static const char* kIsolateReloadTestLibSource = |
228 | "void reloadTest() native 'Test_Reload';\n" |
229 | "void collectNewSpace() native 'Test_CollectNewSpace';\n" |
230 | "void collectOldSpace() native 'Test_CollectOldSpace';\n" ; |
231 | |
232 | static const char* IsolateReloadTestLibUri() { |
233 | return "test:isolate_reload_helper" ; |
234 | } |
235 | |
236 | #define RELOAD_NATIVE_LIST(V) \ |
237 | V(Test_Reload, 0) \ |
238 | V(Test_CollectNewSpace, 0) \ |
239 | V(Test_CollectOldSpace, 0) |
240 | |
241 | RELOAD_NATIVE_LIST(DECLARE_FUNCTION); |
242 | |
243 | static struct NativeEntries { |
244 | const char* name_; |
245 | Dart_NativeFunction function_; |
246 | int argument_count_; |
247 | } ReloadEntries[] = {RELOAD_NATIVE_LIST(REGISTER_FUNCTION)}; |
248 | |
249 | static Dart_NativeFunction IsolateReloadTestNativeResolver( |
250 | Dart_Handle name, |
251 | int argument_count, |
252 | bool* auto_setup_scope) { |
253 | const char* function_name = NULL; |
254 | Dart_Handle result = Dart_StringToCString(name, &function_name); |
255 | ASSERT(!Dart_IsError(result)); |
256 | ASSERT(function_name != NULL); |
257 | ASSERT(auto_setup_scope != NULL); |
258 | *auto_setup_scope = true; |
259 | int num_entries = sizeof(ReloadEntries) / sizeof(struct NativeEntries); |
260 | for (int i = 0; i < num_entries; i++) { |
261 | struct NativeEntries* entry = &(ReloadEntries[i]); |
262 | if ((strcmp(function_name, entry->name_) == 0) && |
263 | (entry->argument_count_ == argument_count)) { |
264 | return reinterpret_cast<Dart_NativeFunction>(entry->function_); |
265 | } |
266 | } |
267 | return NULL; |
268 | } |
269 | |
270 | void FUNCTION_NAME(Test_Reload)(Dart_NativeArguments native_args) { |
271 | Dart_Handle result = TestCase::TriggerReload(/* kernel_buffer= */ NULL, |
272 | /* kernel_buffer_size= */ 0); |
273 | if (Dart_IsError(result)) { |
274 | Dart_PropagateError(result); |
275 | } |
276 | } |
277 | |
278 | void FUNCTION_NAME(Test_CollectNewSpace)(Dart_NativeArguments native_args) { |
279 | TransitionNativeToVM transition(Thread::Current()); |
280 | GCTestHelper::CollectNewSpace(); |
281 | } |
282 | |
283 | void FUNCTION_NAME(Test_CollectOldSpace)(Dart_NativeArguments native_args) { |
284 | TransitionNativeToVM transition(Thread::Current()); |
285 | GCTestHelper::CollectOldSpace(); |
286 | } |
287 | |
288 | static Dart_Handle LoadIsolateReloadTestLib() { |
289 | return TestCase::LoadTestLibrary(IsolateReloadTestLibUri(), |
290 | kIsolateReloadTestLibSource, |
291 | IsolateReloadTestNativeResolver); |
292 | } |
293 | #endif // !PRODUCT |
294 | |
295 | char* TestCase::CompileTestScriptWithDFE(const char* url, |
296 | const char* source, |
297 | const uint8_t** kernel_buffer, |
298 | intptr_t* kernel_buffer_size, |
299 | bool incrementally, |
300 | bool allow_compile_errors, |
301 | const char* multiroot_filepaths, |
302 | const char* multiroot_scheme) { |
303 | // clang-format off |
304 | Dart_SourceFile sourcefiles[] = { |
305 | { |
306 | url, source, |
307 | }, |
308 | { |
309 | "file:///.packages" , "" |
310 | }}; |
311 | // clang-format on |
312 | return CompileTestScriptWithDFE( |
313 | url, sizeof(sourcefiles) / sizeof(Dart_SourceFile), sourcefiles, |
314 | kernel_buffer, kernel_buffer_size, incrementally, allow_compile_errors, |
315 | multiroot_filepaths, multiroot_scheme); |
316 | } |
317 | |
318 | char* TestCase::CompileTestScriptWithDFE(const char* url, |
319 | int sourcefiles_count, |
320 | Dart_SourceFile sourcefiles[], |
321 | const uint8_t** kernel_buffer, |
322 | intptr_t* kernel_buffer_size, |
323 | bool incrementally, |
324 | bool allow_compile_errors, |
325 | const char* multiroot_filepaths, |
326 | const char* multiroot_scheme) { |
327 | Zone* zone = Thread::Current()->zone(); |
328 | Dart_KernelCompilationResult result = KernelIsolate::CompileToKernel( |
329 | url, platform_strong_dill, platform_strong_dill_size, sourcefiles_count, |
330 | sourcefiles, incrementally, NULL, multiroot_filepaths, multiroot_scheme); |
331 | if (result.status == Dart_KernelCompilationStatus_Ok) { |
332 | if (KernelIsolate::AcceptCompilation().status != |
333 | Dart_KernelCompilationStatus_Ok) { |
334 | FATAL( |
335 | "An error occurred in the CFE while accepting the most recent" |
336 | " compilation results." ); |
337 | } |
338 | } |
339 | return ValidateCompilationResult(zone, result, kernel_buffer, |
340 | kernel_buffer_size, allow_compile_errors); |
341 | } |
342 | |
343 | char* TestCase::ValidateCompilationResult( |
344 | Zone* zone, |
345 | Dart_KernelCompilationResult compilation_result, |
346 | const uint8_t** kernel_buffer, |
347 | intptr_t* kernel_buffer_size, |
348 | bool allow_compile_errors) { |
349 | if (!allow_compile_errors && |
350 | (compilation_result.status != Dart_KernelCompilationStatus_Ok)) { |
351 | char* result = |
352 | OS::SCreate(zone, "Compilation failed %s" , compilation_result.error); |
353 | free(compilation_result.error); |
354 | if (compilation_result.kernel != NULL) { |
355 | free(const_cast<uint8_t*>(compilation_result.kernel)); |
356 | } |
357 | *kernel_buffer = NULL; |
358 | *kernel_buffer_size = 0; |
359 | return result; |
360 | } |
361 | *kernel_buffer = compilation_result.kernel; |
362 | *kernel_buffer_size = compilation_result.kernel_size; |
363 | if (compilation_result.error != NULL) { |
364 | free(compilation_result.error); |
365 | } |
366 | if (kernel_buffer == NULL) { |
367 | return OS::SCreate(zone, "front end generated a NULL kernel file" ); |
368 | } |
369 | return NULL; |
370 | } |
371 | |
372 | static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag, |
373 | Dart_Handle library, |
374 | Dart_Handle url) { |
375 | if (tag == Dart_kCanonicalizeUrl) { |
376 | Dart_Handle library_url = Dart_LibraryUrl(library); |
377 | if (Dart_IsError(library_url)) { |
378 | return library_url; |
379 | } |
380 | return Dart_DefaultCanonicalizeUrl(library_url, url); |
381 | } |
382 | UNREACHABLE(); |
383 | return Dart_Null(); |
384 | } |
385 | |
386 | static intptr_t BuildSourceFilesArray( |
387 | Dart_SourceFile** sourcefiles, |
388 | const char* script, |
389 | const char* script_url = RESOLVED_USER_TEST_URI) { |
390 | ASSERT(sourcefiles != NULL); |
391 | ASSERT(script != NULL); |
392 | |
393 | intptr_t num_test_libs = 0; |
394 | if (test_libs_ != NULL) { |
395 | num_test_libs = test_libs_->length(); |
396 | } |
397 | |
398 | *sourcefiles = new Dart_SourceFile[num_test_libs + 1]; |
399 | (*sourcefiles)[0].uri = script_url; |
400 | (*sourcefiles)[0].source = script; |
401 | for (intptr_t i = 0; i < num_test_libs; ++i) { |
402 | (*sourcefiles)[i + 1].uri = test_libs_->At(i).url; |
403 | (*sourcefiles)[i + 1].source = test_libs_->At(i).source; |
404 | } |
405 | return num_test_libs + 1; |
406 | } |
407 | |
408 | Dart_Handle TestCase::LoadTestScriptWithErrors( |
409 | const char* script, |
410 | Dart_NativeEntryResolver resolver, |
411 | const char* lib_url, |
412 | bool finalize_classes) { |
413 | return LoadTestScript(script, resolver, lib_url, finalize_classes, true); |
414 | } |
415 | |
416 | Dart_Handle TestCase::LoadTestScript(const char* script, |
417 | Dart_NativeEntryResolver resolver, |
418 | const char* lib_url, |
419 | bool finalize_classes, |
420 | bool allow_compile_errors) { |
421 | #ifndef PRODUCT |
422 | if (strstr(script, IsolateReloadTestLibUri()) != NULL) { |
423 | Dart_Handle result = LoadIsolateReloadTestLib(); |
424 | EXPECT_VALID(result); |
425 | } |
426 | #endif // ifndef PRODUCT |
427 | Dart_SourceFile* sourcefiles = NULL; |
428 | intptr_t num_sources = BuildSourceFilesArray(&sourcefiles, script, lib_url); |
429 | Dart_Handle result = |
430 | LoadTestScriptWithDFE(num_sources, sourcefiles, resolver, |
431 | finalize_classes, true, allow_compile_errors); |
432 | delete[] sourcefiles; |
433 | return result; |
434 | } |
435 | |
436 | Dart_Handle TestCase::LoadTestLibrary(const char* lib_uri, |
437 | const char* script, |
438 | Dart_NativeEntryResolver resolver) { |
439 | const char* prefixed_lib_uri = |
440 | OS::SCreate(Thread::Current()->zone(), "file:///%s" , lib_uri); |
441 | Dart_SourceFile sourcefiles[] = {{prefixed_lib_uri, script}}; |
442 | const uint8_t* kernel_buffer = NULL; |
443 | intptr_t kernel_buffer_size = 0; |
444 | int sourcefiles_count = sizeof(sourcefiles) / sizeof(Dart_SourceFile); |
445 | char* error = TestCase::CompileTestScriptWithDFE( |
446 | sourcefiles[0].uri, sourcefiles_count, sourcefiles, &kernel_buffer, |
447 | &kernel_buffer_size, true); |
448 | if ((kernel_buffer == NULL) && (error != NULL)) { |
449 | return Dart_NewApiError(error); |
450 | } |
451 | Dart_Handle lib = |
452 | Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size); |
453 | EXPECT_VALID(lib); |
454 | |
455 | // Ensure kernel buffer isn't leaked after test is run. |
456 | AddToKernelBuffers(kernel_buffer); |
457 | |
458 | // TODO(32618): Kernel doesn't correctly represent the root library. |
459 | lib = Dart_LookupLibrary(Dart_NewStringFromCString(sourcefiles[0].uri)); |
460 | EXPECT_VALID(lib); |
461 | Dart_Handle result = Dart_SetRootLibrary(lib); |
462 | EXPECT_VALID(result); |
463 | |
464 | Dart_SetNativeResolver(lib, resolver, NULL); |
465 | return lib; |
466 | } |
467 | |
468 | Dart_Handle TestCase::LoadTestScriptWithDFE(int sourcefiles_count, |
469 | Dart_SourceFile sourcefiles[], |
470 | Dart_NativeEntryResolver resolver, |
471 | bool finalize, |
472 | bool incrementally, |
473 | bool allow_compile_errors, |
474 | const char* entry_script_uri, |
475 | const char* multiroot_filepaths, |
476 | const char* multiroot_scheme) { |
477 | // First script is the main script. |
478 | Dart_Handle result = Dart_SetLibraryTagHandler(LibraryTagHandler); |
479 | EXPECT_VALID(result); |
480 | const uint8_t* kernel_buffer = NULL; |
481 | intptr_t kernel_buffer_size = 0; |
482 | char* error = TestCase::CompileTestScriptWithDFE( |
483 | entry_script_uri != NULL ? entry_script_uri : sourcefiles[0].uri, |
484 | sourcefiles_count, sourcefiles, &kernel_buffer, &kernel_buffer_size, |
485 | incrementally, allow_compile_errors, multiroot_filepaths, |
486 | multiroot_scheme); |
487 | if ((kernel_buffer == NULL) && error != NULL) { |
488 | return Dart_NewApiError(error); |
489 | } |
490 | |
491 | Dart_Handle lib = |
492 | Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size); |
493 | EXPECT_VALID(lib); |
494 | |
495 | // Ensure kernel buffer isn't leaked after test is run. |
496 | AddToKernelBuffers(kernel_buffer); |
497 | |
498 | // BOGUS: Kernel doesn't correctly represent the root library. |
499 | lib = Dart_LookupLibrary(Dart_NewStringFromCString( |
500 | entry_script_uri != NULL ? entry_script_uri : sourcefiles[0].uri)); |
501 | EXPECT_VALID(lib); |
502 | result = Dart_SetRootLibrary(lib); |
503 | EXPECT_VALID(result); |
504 | |
505 | result = Dart_SetNativeResolver(lib, resolver, NULL); |
506 | EXPECT_VALID(result); |
507 | if (finalize) { |
508 | result = Dart_FinalizeLoading(false); |
509 | EXPECT_VALID(result); |
510 | } |
511 | return lib; |
512 | } |
513 | |
514 | #ifndef PRODUCT |
515 | |
516 | Dart_Handle TestCase::SetReloadTestScript(const char* script) { |
517 | // For our vm/cc/IsolateReload_* tests we flip the GC flag on, which will |
518 | // cause the isolate reload to do GCs before/after morphing, etc. |
519 | FLAG_gc_during_reload = true; |
520 | FLAG_force_evacuation = true; |
521 | |
522 | Dart_SourceFile* sourcefiles = NULL; |
523 | intptr_t num_files = BuildSourceFilesArray(&sourcefiles, script); |
524 | Dart_KernelCompilationResult compilation_result = |
525 | KernelIsolate::UpdateInMemorySources(num_files, sourcefiles); |
526 | delete[] sourcefiles; |
527 | if (compilation_result.status != Dart_KernelCompilationStatus_Ok) { |
528 | Dart_Handle result = Dart_NewApiError(compilation_result.error); |
529 | free(compilation_result.error); |
530 | return result; |
531 | } |
532 | return Api::Success(); |
533 | } |
534 | |
535 | Dart_Handle TestCase::TriggerReload(const uint8_t* kernel_buffer, |
536 | intptr_t kernel_buffer_size) { |
537 | Thread* thread = Thread::Current(); |
538 | Isolate* isolate = thread->isolate(); |
539 | JSONStream js; |
540 | bool success = false; |
541 | { |
542 | TransitionNativeToVM transition(thread); |
543 | success = |
544 | isolate->group()->ReloadKernel(&js, |
545 | false, // force_reload |
546 | kernel_buffer, kernel_buffer_size, |
547 | true); // dont_delete_reload_context |
548 | OS::PrintErr("RELOAD REPORT:\n%s\n" , js.ToCString()); |
549 | } |
550 | |
551 | Dart_Handle result = Dart_Null(); |
552 | if (success) { |
553 | result = Dart_FinalizeLoading(false); |
554 | } |
555 | |
556 | if (Dart_IsError(result)) { |
557 | // Keep load error. |
558 | } else if (isolate->group()->reload_context()->reload_aborted()) { |
559 | TransitionNativeToVM transition(thread); |
560 | result = Api::NewHandle( |
561 | thread, isolate->reload_context()->group_reload_context()->error()); |
562 | } else { |
563 | result = Dart_RootLibrary(); |
564 | } |
565 | |
566 | TransitionNativeToVM transition(thread); |
567 | if (isolate->reload_context() != NULL) { |
568 | isolate->DeleteReloadContext(); |
569 | isolate->group()->DeleteReloadContext(); |
570 | } |
571 | |
572 | return result; |
573 | } |
574 | |
575 | Dart_Handle TestCase::ReloadTestScript(const char* script) { |
576 | Dart_SourceFile* sourcefiles = NULL; |
577 | intptr_t num_files = BuildSourceFilesArray(&sourcefiles, script); |
578 | Dart_KernelCompilationResult compilation_result = |
579 | KernelIsolate::UpdateInMemorySources(num_files, sourcefiles); |
580 | delete[] sourcefiles; |
581 | if (compilation_result.status != Dart_KernelCompilationStatus_Ok) { |
582 | Dart_Handle result = Dart_NewApiError(compilation_result.error); |
583 | free(compilation_result.error); |
584 | if (compilation_result.kernel != NULL) { |
585 | free(const_cast<uint8_t*>(compilation_result.kernel)); |
586 | } |
587 | return result; |
588 | } |
589 | |
590 | return TriggerReload(/* kernel_buffer= */ NULL, /* kernel_buffer_size= */ 0); |
591 | } |
592 | |
593 | Dart_Handle TestCase::ReloadTestKernel(const uint8_t* kernel_buffer, |
594 | intptr_t kernel_buffer_size) { |
595 | return TriggerReload(kernel_buffer, kernel_buffer_size); |
596 | } |
597 | |
598 | #endif // !PRODUCT |
599 | |
600 | Dart_Handle TestCase::LoadCoreTestScript(const char* script, |
601 | Dart_NativeEntryResolver resolver) { |
602 | return LoadTestScript(script, resolver, CORELIB_TEST_URI); |
603 | } |
604 | |
605 | Dart_Handle TestCase::lib() { |
606 | Dart_Handle url = NewString(TestCase::url()); |
607 | Dart_Handle lib = Dart_LookupLibrary(url); |
608 | EXPECT_VALID(lib); |
609 | ASSERT(Dart_IsLibrary(lib)); |
610 | return lib; |
611 | } |
612 | |
613 | Dart_Handle TestCase::library_handler(Dart_LibraryTag tag, |
614 | Dart_Handle library, |
615 | Dart_Handle url) { |
616 | if (tag == Dart_kCanonicalizeUrl) { |
617 | return url; |
618 | } |
619 | return Api::Success(); |
620 | } |
621 | |
622 | Dart_Handle TestCase::EvaluateExpression(const Library& lib, |
623 | const String& expr, |
624 | const Array& param_names, |
625 | const Array& param_values) { |
626 | Thread* thread = Thread::Current(); |
627 | |
628 | Object& val = Object::Handle(); |
629 | if (!KernelIsolate::IsRunning()) { |
630 | UNREACHABLE(); |
631 | } else { |
632 | Dart_KernelCompilationResult compilation_result = |
633 | KernelIsolate::CompileExpressionToKernel( |
634 | /* platform_kernel= */ nullptr, /* platform_kernel_size= */ 0, |
635 | expr.ToCString(), param_names, Array::empty_array(), |
636 | String::Handle(lib.url()).ToCString(), /* klass=*/nullptr, |
637 | /* is_static= */ true); |
638 | if (compilation_result.status != Dart_KernelCompilationStatus_Ok) { |
639 | return Api::NewError("%s" , compilation_result.error); |
640 | } |
641 | |
642 | const ExternalTypedData& kernel_buffer = |
643 | ExternalTypedData::Handle(ExternalTypedData::NewFinalizeWithFree( |
644 | const_cast<uint8_t*>(compilation_result.kernel), |
645 | compilation_result.kernel_size)); |
646 | |
647 | val = lib.EvaluateCompiledExpression(kernel_buffer, Array::empty_array(), |
648 | param_values, |
649 | TypeArguments::null_type_arguments()); |
650 | } |
651 | return Api::NewHandle(thread, val.raw()); |
652 | } |
653 | |
654 | #if !defined(PRODUCT) |
655 | static bool IsHex(int c) { |
656 | return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f'); |
657 | } |
658 | #endif |
659 | |
660 | void AssemblerTest::Assemble() { |
661 | const String& function_name = |
662 | String::ZoneHandle(Symbols::New(Thread::Current(), name_)); |
663 | |
664 | // We make a dummy script so that exception objects can be composed for |
665 | // assembler instructions that do runtime calls. |
666 | const char* kDummyScript = "assembler_test_dummy_function() {}" ; |
667 | const Script& script = Script::Handle( |
668 | Script::New(function_name, String::Handle(String::New(kDummyScript)))); |
669 | const Library& lib = Library::Handle(Library::CoreLibrary()); |
670 | const Class& cls = Class::ZoneHandle( |
671 | Class::New(lib, function_name, script, TokenPosition::kMinSource)); |
672 | Function& function = Function::ZoneHandle(Function::New( |
673 | function_name, FunctionLayout::kRegularFunction, true, false, false, |
674 | false, false, cls, TokenPosition::kMinSource)); |
675 | code_ = Code::FinalizeCodeAndNotify(function, nullptr, assembler_, |
676 | Code::PoolAttachment::kAttachPool); |
677 | code_.set_owner(function); |
678 | code_.set_exception_handlers(Object::empty_exception_handlers()); |
679 | #ifndef PRODUCT |
680 | uword start = code_.PayloadStart(); |
681 | if (FLAG_disassemble) { |
682 | OS::PrintErr("Code for test '%s' {\n" , name_); |
683 | Disassembler::Disassemble(start, start + assembler_->CodeSize()); |
684 | OS::PrintErr("}\n" ); |
685 | } |
686 | Disassembler::Disassemble(start, start + assembler_->CodeSize(), disassembly_, |
687 | DISASSEMBLY_SIZE); |
688 | // Blank out big hex constants, since they are not stable from run to run. |
689 | bool in_hex_constant = false; |
690 | for (char* p = disassembly_; *p != '\0'; p++) { |
691 | if (in_hex_constant) { |
692 | if (IsHex(*p)) { |
693 | *p = '.'; |
694 | } else { |
695 | in_hex_constant = false; |
696 | } |
697 | } else { |
698 | if (*p == '0' && *(p + 1) == 'x' && IsHex(*(p + 2)) && IsHex(*(p + 3)) && |
699 | IsHex(*(p + 4))) { |
700 | p++; |
701 | in_hex_constant = true; |
702 | } |
703 | } |
704 | } |
705 | #endif // !PRODUCT |
706 | } |
707 | |
708 | bool CompilerTest::TestCompileFunction(const Function& function) { |
709 | Thread* thread = Thread::Current(); |
710 | ASSERT(thread != NULL); |
711 | ASSERT(ClassFinalizer::AllClassesFinalized()); |
712 | const Object& result = |
713 | Object::Handle(Compiler::CompileFunction(thread, function)); |
714 | return result.IsCode(); |
715 | } |
716 | |
717 | void ElideJSONSubstring(const char* prefix, const char* in, char* out) { |
718 | const char* pos = strstr(in, prefix); |
719 | while (pos != NULL) { |
720 | // Copy up to pos into the output buffer. |
721 | while (in < pos) { |
722 | *out++ = *in++; |
723 | } |
724 | |
725 | // Skip to the close quote. |
726 | in += strcspn(in, "\"" ); |
727 | pos = strstr(in, prefix); |
728 | } |
729 | // Copy the remainder of in to out. |
730 | while (*in != '\0') { |
731 | *out++ = *in++; |
732 | } |
733 | *out = '\0'; |
734 | } |
735 | |
736 | } // namespace dart |
737 | |