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 "vm/kernel_isolate.h"
6
7#include "include/dart_native_api.h"
8#include "vm/compiler/jit/compiler.h"
9#include "vm/dart_api_impl.h"
10#include "vm/dart_entry.h"
11#include "vm/flags.h"
12#include "vm/isolate.h"
13#include "vm/lockers.h"
14#include "vm/message.h"
15#include "vm/message_handler.h"
16#include "vm/native_arguments.h"
17#include "vm/native_entry.h"
18#include "vm/native_message_handler.h"
19#include "vm/object.h"
20#include "vm/object_store.h"
21#include "vm/port.h"
22#include "vm/service.h"
23#include "vm/symbols.h"
24#include "vm/thread_pool.h"
25#include "vm/timeline.h"
26
27#if !defined(DART_PRECOMPILED_RUNTIME)
28
29namespace dart {
30
31#define Z (T->zone())
32
33DEFINE_FLAG(bool, trace_kernel, false, "Trace Kernel service requests.");
34DEFINE_FLAG(bool,
35 suppress_fe_warnings,
36 false,
37 "Suppress warnings from the FE.");
38DEFINE_FLAG(charp,
39 kernel_multiroot_filepaths,
40 NULL,
41 "Comma-separated list of file paths that should be treated as roots"
42 " by frontend compiler.");
43DEFINE_FLAG(charp,
44 kernel_multiroot_scheme,
45 NULL,
46 "URI scheme that replaces filepaths prefixes specified"
47 " by kernel_multiroot_filepaths option");
48
49// Tags used to indicate different requests to the dart frontend.
50//
51// Current tags include the following:
52// 0 - Perform normal compilation.
53// 1 - Update in-memory file system with in-memory sources (used by tests).
54// 2 - Accept last compilation result.
55// 3 - APP JIT snapshot training run for kernel_service.
56// 4 - Compile expressions in context (used by expression evaluation).
57// 5 - Generate dependencies used to create a dependencies file.
58// 6 - Triggers shutdown of the kernel isolate.
59// 7 - Detects the nullability of a script based on it's opt-in status.
60const int KernelIsolate::kCompileTag = 0;
61const int KernelIsolate::kUpdateSourcesTag = 1;
62const int KernelIsolate::kAcceptTag = 2;
63const int KernelIsolate::kTrainTag = 3;
64const int KernelIsolate::kCompileExpressionTag = 4;
65const int KernelIsolate::kListDependenciesTag = 5;
66const int KernelIsolate::kNotifyIsolateShutdown = 6;
67const int KernelIsolate::kDetectNullabilityTag = 7;
68
69const char* KernelIsolate::kName = DART_KERNEL_ISOLATE_NAME;
70Dart_IsolateGroupCreateCallback KernelIsolate::create_group_callback_ = NULL;
71Monitor* KernelIsolate::monitor_ = new Monitor();
72KernelIsolate::State KernelIsolate::state_ = KernelIsolate::kNotStarted;
73Isolate* KernelIsolate::isolate_ = NULL;
74Dart_Port KernelIsolate::kernel_port_ = ILLEGAL_PORT;
75
76class RunKernelTask : public ThreadPool::Task {
77 public:
78 virtual void Run() {
79 ASSERT(Isolate::Current() == NULL);
80#ifdef SUPPORT_TIMELINE
81 TimelineBeginEndScope tbes(Timeline::GetVMStream(), "KernelIsolateStartup");
82#endif // SUPPORT_TIMELINE
83 char* error = NULL;
84 Isolate* isolate = NULL;
85
86 Dart_IsolateGroupCreateCallback create_group_callback =
87 KernelIsolate::create_group_callback();
88 ASSERT(create_group_callback != NULL);
89
90 // Note: these flags must match those passed to the VM during
91 // the app-jit training run (see //utils/kernel-service/BUILD.gn).
92 Dart_IsolateFlags api_flags;
93 Isolate::FlagsInitialize(&api_flags);
94 api_flags.enable_asserts = false;
95#if !defined(DART_PRECOMPILER)
96 api_flags.use_field_guards = true;
97#endif
98#if !defined(DART_PRECOMPILER)
99 api_flags.use_osr = true;
100#endif
101
102 isolate = reinterpret_cast<Isolate*>(
103 create_group_callback(KernelIsolate::kName, KernelIsolate::kName, NULL,
104 NULL, &api_flags, NULL, &error));
105 if (isolate == NULL) {
106 if (FLAG_trace_kernel) {
107 OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Isolate creation error: %s\n",
108 error);
109 }
110 free(error);
111 error = nullptr;
112 KernelIsolate::SetKernelIsolate(NULL);
113 KernelIsolate::InitializingFailed();
114 return;
115 }
116
117 bool got_unwind;
118 {
119 ASSERT(Isolate::Current() == NULL);
120 StartIsolateScope start_scope(isolate);
121 got_unwind = RunMain(isolate);
122 }
123 KernelIsolate::FinishedInitializing();
124
125 if (got_unwind) {
126 ShutdownIsolate(reinterpret_cast<uword>(isolate));
127 return;
128 }
129
130 // isolate_ was set as side effect of create callback.
131 ASSERT(KernelIsolate::IsKernelIsolate(isolate));
132
133 isolate->message_handler()->Run(Dart::thread_pool(), NULL, ShutdownIsolate,
134 reinterpret_cast<uword>(isolate));
135 }
136
137 protected:
138 static void ShutdownIsolate(uword parameter) {
139 if (FLAG_trace_kernel) {
140 OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": ShutdownIsolate\n");
141 }
142 Isolate* I = reinterpret_cast<Isolate*>(parameter);
143 {
144 // Print the error if there is one. This may execute dart code to
145 // print the exception object, so we need to use a StartIsolateScope.
146 ASSERT(Isolate::Current() == NULL);
147 StartIsolateScope start_scope(I);
148 Thread* T = Thread::Current();
149 ASSERT(I == T->isolate());
150 I->WaitForOutstandingSpawns();
151 StackZone zone(T);
152 HandleScope handle_scope(T);
153 Error& error = Error::Handle(Z);
154 error = T->sticky_error();
155 if (!error.IsNull() && !error.IsUnwindError()) {
156 OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Error: %s\n",
157 error.ToErrorCString());
158 }
159 error = I->sticky_error();
160 if (!error.IsNull() && !error.IsUnwindError()) {
161 OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Error: %s\n",
162 error.ToErrorCString());
163 }
164 Dart::RunShutdownCallback();
165 }
166
167 ASSERT(KernelIsolate::IsKernelIsolate(I));
168 KernelIsolate::SetLoadPort(ILLEGAL_PORT);
169
170 // Shut the isolate down.
171 Dart::ShutdownIsolate(I);
172 if (FLAG_trace_kernel) {
173 OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Shutdown.\n");
174 }
175 KernelIsolate::FinishedExiting();
176 }
177
178 bool RunMain(Isolate* I) {
179 Thread* T = Thread::Current();
180 ASSERT(I == T->isolate());
181 StackZone zone(T);
182 HANDLESCOPE(T);
183 // Invoke main which will return the port to which load requests are sent.
184 const Library& root_library =
185 Library::Handle(Z, I->object_store()->root_library());
186 if (root_library.IsNull()) {
187 OS::PrintErr(DART_KERNEL_ISOLATE_NAME
188 ": Embedder did not install a script.");
189 // Kernel isolate is not supported by embedder.
190 return false;
191 }
192 ASSERT(!root_library.IsNull());
193 const String& entry_name = String::Handle(Z, String::New("main"));
194 ASSERT(!entry_name.IsNull());
195 const Function& entry = Function::Handle(
196 Z, root_library.LookupFunctionAllowPrivate(entry_name));
197 if (entry.IsNull()) {
198 // Kernel isolate is not supported by embedder.
199 OS::PrintErr(DART_KERNEL_ISOLATE_NAME
200 ": Embedder did not provide a main function.");
201 return false;
202 }
203 ASSERT(!entry.IsNull());
204 const Object& result = Object::Handle(
205 Z, DartEntry::InvokeFunction(entry, Object::empty_array()));
206 ASSERT(!result.IsNull());
207 if (result.IsError()) {
208 // Kernel isolate did not initialize properly.
209 if (FLAG_trace_kernel) {
210 const Error& error = Error::Cast(result);
211 OS::PrintErr(DART_KERNEL_ISOLATE_NAME
212 ": Calling main resulted in an error: %s",
213 error.ToErrorCString());
214 }
215 if (result.IsUnwindError()) {
216 return true;
217 }
218 return false;
219 }
220 ASSERT(result.IsReceivePort());
221 const ReceivePort& rp = ReceivePort::Cast(result);
222 KernelIsolate::SetLoadPort(rp.Id());
223 return false;
224 }
225};
226
227void KernelIsolate::InitializeState() {
228 // Grab the isolate create callback here to avoid race conditions with tests
229 // that change this after Dart_Initialize returns.
230 if (FLAG_trace_kernel) {
231 OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": InitializeState\n");
232 }
233 create_group_callback_ = Isolate::CreateGroupCallback();
234 if (create_group_callback_ == NULL) {
235 KernelIsolate::InitializingFailed();
236 return;
237 }
238}
239
240bool KernelIsolate::Start() {
241 if (create_group_callback_ == nullptr) {
242 if (FLAG_trace_kernel) {
243 OS::PrintErr(DART_KERNEL_ISOLATE_NAME
244 ": Attempted to start kernel isolate without setting "
245 "Dart_InitializeParams property 'start_kernel_isolate' "
246 "to true\n");
247 }
248 return false;
249 }
250 bool start_task = false;
251 {
252 MonitorLocker ml(monitor_);
253 if (state_ == kNotStarted) {
254 if (FLAG_trace_kernel) {
255 OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Start\n");
256 }
257 start_task = true;
258 state_ = kStarting;
259 ml.NotifyAll();
260 }
261 }
262 bool task_started = true;
263 if (start_task) {
264 task_started = Dart::thread_pool()->Run<RunKernelTask>();
265 }
266 return task_started;
267}
268
269void KernelIsolate::Shutdown() {
270 MonitorLocker ml(monitor_);
271 while (state_ == kStarting) {
272 ml.Wait();
273 }
274 if (state_ == kStopped || state_ == kNotStarted) {
275 return;
276 }
277 ASSERT(state_ == kStarted);
278 state_ = kStopping;
279 ml.NotifyAll();
280 Isolate::KillIfExists(isolate_, Isolate::kInternalKillMsg);
281 while (state_ != kStopped) {
282 ml.Wait();
283 }
284}
285
286void KernelIsolate::InitCallback(Isolate* I) {
287 Thread* T = Thread::Current();
288 ASSERT(I == T->isolate());
289 ASSERT(I != NULL);
290 if (!NameEquals(I->name())) {
291 // Not kernel isolate.
292 return;
293 }
294 ASSERT(!Exists());
295 if (FLAG_trace_kernel) {
296 OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": InitCallback for %s.\n",
297 I->name());
298 }
299 SetKernelIsolate(I);
300}
301
302bool KernelIsolate::IsKernelIsolate(const Isolate* isolate) {
303 MonitorLocker ml(monitor_);
304 return isolate == isolate_;
305}
306
307bool KernelIsolate::IsRunning() {
308 MonitorLocker ml(monitor_);
309 return (kernel_port_ != ILLEGAL_PORT) && (isolate_ != NULL);
310}
311
312bool KernelIsolate::NameEquals(const char* name) {
313 ASSERT(name != NULL);
314 return (strcmp(name, DART_KERNEL_ISOLATE_NAME) == 0);
315}
316
317bool KernelIsolate::Exists() {
318 MonitorLocker ml(monitor_);
319 return isolate_ != NULL;
320}
321
322void KernelIsolate::SetKernelIsolate(Isolate* isolate) {
323 MonitorLocker ml(monitor_);
324 if (isolate != nullptr) {
325 isolate->set_is_kernel_isolate(true);
326 }
327 isolate_ = isolate;
328 ml.NotifyAll();
329}
330
331void KernelIsolate::SetLoadPort(Dart_Port port) {
332 MonitorLocker ml(monitor_);
333 kernel_port_ = port;
334 ml.NotifyAll();
335}
336
337void KernelIsolate::FinishedExiting() {
338 MonitorLocker ml(monitor_);
339 ASSERT(state_ == kStarted || state_ == kStopping);
340 state_ = kStopped;
341 ml.NotifyAll();
342}
343
344void KernelIsolate::FinishedInitializing() {
345 MonitorLocker ml(monitor_);
346 ASSERT(state_ == kStarting);
347 state_ = kStarted;
348 ml.NotifyAll();
349}
350
351void KernelIsolate::InitializingFailed() {
352 MonitorLocker ml(monitor_);
353 ASSERT(state_ == kStarting);
354 state_ = kStopped;
355 ml.NotifyAll();
356}
357
358Dart_Port KernelIsolate::WaitForKernelPort() {
359 VMTagScope tagScope(Thread::Current(), VMTag::kLoadWaitTagId);
360 MonitorLocker ml(monitor_);
361 while (state_ == kStarting && (kernel_port_ == ILLEGAL_PORT)) {
362 ml.Wait();
363 }
364 return kernel_port_;
365}
366
367static Dart_CObject BuildFilesPairs(int source_files_count,
368 Dart_SourceFile source_files[]) {
369 Dart_CObject files;
370 files.type = Dart_CObject_kArray;
371 files.value.as_array.length = source_files_count * 2;
372 // typedef Dart_CObject* Dart_CObjectPtr;
373 Dart_CObject** fileNamePairs = new Dart_CObject*[source_files_count * 2];
374 for (int i = 0; i < source_files_count; i++) {
375 Dart_CObject* source_uri = new Dart_CObject();
376 source_uri->type = Dart_CObject_kString;
377 source_uri->value.as_string = const_cast<char*>(source_files[i].uri);
378 fileNamePairs[i * 2] = source_uri;
379 Dart_CObject* source_code = new Dart_CObject();
380
381 if (source_files[i].source != NULL) {
382 source_code->type = Dart_CObject_kTypedData;
383 source_code->value.as_typed_data.type = Dart_TypedData_kUint8;
384 source_code->value.as_typed_data.length = strlen(source_files[i].source);
385 source_code->value.as_typed_data.values =
386 reinterpret_cast<uint8_t*>(const_cast<char*>(source_files[i].source));
387 } else {
388 source_code->type = Dart_CObject_kNull;
389 }
390 fileNamePairs[(i * 2) + 1] = source_code;
391 }
392 files.value.as_array.values = fileNamePairs;
393 return files;
394}
395
396static void ReleaseFilesPairs(const Dart_CObject& files) {
397 for (intptr_t i = 0; i < files.value.as_array.length; i++) {
398 delete files.value.as_array.values[i];
399 }
400 delete[] files.value.as_array.values;
401}
402
403static void PassThroughFinalizer(void* isolate_callback_data,
404 Dart_WeakPersistentHandle handle,
405 void* peer) {}
406
407MallocGrowableArray<char*>* KernelIsolate::experimental_flags_ =
408 new MallocGrowableArray<char*>();
409
410void KernelIsolate::AddExperimentalFlag(const char* value) {
411 char* save_ptr; // Needed for strtok_r.
412 char* temp = Utils::StrDup(value);
413 char* token = strtok_r(temp, ",", &save_ptr);
414 while (token != NULL) {
415 experimental_flags_->Add(Utils::StrDup(token));
416 token = strtok_r(NULL, ",", &save_ptr);
417 }
418 free(temp);
419}
420
421bool KernelIsolate::GetExperimentalFlag(const char* value) {
422 for (const char* str : *experimental_flags_) {
423 if (strcmp(str, value) == 0) {
424 return true;
425 }
426 }
427 return false;
428}
429
430DEFINE_OPTION_HANDLER(KernelIsolate::AddExperimentalFlag,
431 enable_experiment,
432 "Comma separated list of experimental features.");
433
434class KernelCompilationRequest : public ValueObject {
435 public:
436 KernelCompilationRequest()
437 : monitor_(),
438 port_(Dart_NewNativePort("kernel-compilation-port",
439 &HandleResponse,
440 false)),
441 next_(NULL),
442 prev_(NULL) {
443 ASSERT(port_ != ILLEGAL_PORT);
444 RegisterRequest(this);
445 result_.status = Dart_KernelCompilationStatus_Unknown;
446 result_.error = NULL;
447 result_.kernel = NULL;
448 result_.kernel_size = 0;
449 }
450
451 ~KernelCompilationRequest() {
452 UnregisterRequest(this);
453 Dart_CloseNativePort(port_);
454 }
455
456 intptr_t setDillData(Dart_CObject** dills_array,
457 intptr_t dill_num,
458 const uint8_t* buffer,
459 intptr_t buffer_size) {
460 if (buffer != nullptr) {
461 dills_array[dill_num] = new Dart_CObject;
462 dills_array[dill_num]->type = Dart_CObject_kExternalTypedData;
463 dills_array[dill_num]->value.as_external_typed_data.type =
464 Dart_TypedData_kUint8;
465 dills_array[dill_num]->value.as_external_typed_data.length = buffer_size;
466 dills_array[dill_num]->value.as_external_typed_data.data =
467 const_cast<uint8_t*>(buffer);
468 dills_array[dill_num]->value.as_external_typed_data.peer =
469 const_cast<uint8_t*>(buffer);
470 dills_array[dill_num]->value.as_external_typed_data.callback =
471 PassThroughFinalizer;
472 dill_num++;
473 }
474 return dill_num;
475 }
476
477 Dart_KernelCompilationResult SendAndWaitForResponse(
478 Dart_Port kernel_port,
479 const uint8_t* platform_kernel,
480 intptr_t platform_kernel_size,
481 const char* expression,
482 const Array& definitions,
483 const Array& type_definitions,
484 char const* library_uri,
485 char const* klass,
486 bool is_static,
487 const MallocGrowableArray<char*>* experimental_flags) {
488 Thread* thread = Thread::Current();
489 TransitionNativeToVM transition(thread);
490 Dart_CObject tag;
491 tag.type = Dart_CObject_kInt32;
492 tag.value.as_int32 = KernelIsolate::kCompileExpressionTag;
493
494 Dart_CObject send_port;
495 send_port.type = Dart_CObject_kSendPort;
496 send_port.value.as_send_port.id = port_;
497 send_port.value.as_send_port.origin_id = ILLEGAL_PORT;
498
499 Dart_CObject dart_platform_kernel;
500 if (platform_kernel != NULL) {
501 dart_platform_kernel.type = Dart_CObject_kExternalTypedData;
502 dart_platform_kernel.value.as_external_typed_data.type =
503 Dart_TypedData_kUint8;
504 dart_platform_kernel.value.as_external_typed_data.length =
505 platform_kernel_size;
506 dart_platform_kernel.value.as_external_typed_data.data =
507 const_cast<uint8_t*>(platform_kernel);
508 dart_platform_kernel.value.as_external_typed_data.peer =
509 const_cast<uint8_t*>(platform_kernel);
510 dart_platform_kernel.value.as_external_typed_data.callback =
511 PassThroughFinalizer;
512 } else {
513 // If NULL, the kernel service looks up the platform dill file
514 // next to the executable.
515 dart_platform_kernel.type = Dart_CObject_kNull;
516 }
517
518 Dart_CObject expression_object;
519 expression_object.type = Dart_CObject_kString;
520 expression_object.value.as_string = const_cast<char*>(expression);
521
522 Dart_CObject definitions_object;
523 intptr_t num_definitions = definitions.Length();
524 definitions_object.type = Dart_CObject_kArray;
525 definitions_object.value.as_array.length = num_definitions;
526
527 Dart_CObject** definitions_array = new Dart_CObject*[num_definitions];
528 for (intptr_t i = 0; i < num_definitions; ++i) {
529 definitions_array[i] = new Dart_CObject;
530 definitions_array[i]->type = Dart_CObject_kString;
531 definitions_array[i]->value.as_string = const_cast<char*>(
532 String::CheckedHandle(thread->zone(), definitions.At(i)).ToCString());
533 }
534 definitions_object.value.as_array.values = definitions_array;
535
536 Dart_CObject type_definitions_object;
537 intptr_t num_type_definitions = type_definitions.Length();
538 type_definitions_object.type = Dart_CObject_kArray;
539 type_definitions_object.value.as_array.length = num_type_definitions;
540
541 Dart_CObject** type_definitions_array =
542 new Dart_CObject*[num_type_definitions];
543 for (intptr_t i = 0; i < num_type_definitions; ++i) {
544 type_definitions_array[i] = new Dart_CObject;
545 type_definitions_array[i]->type = Dart_CObject_kString;
546 type_definitions_array[i]->value.as_string = const_cast<char*>(
547 String::CheckedHandle(thread->zone(), type_definitions.At(i))
548 .ToCString());
549 }
550 type_definitions_object.value.as_array.values = type_definitions_array;
551
552 Dart_CObject library_uri_object;
553 library_uri_object.type = Dart_CObject_kString;
554 library_uri_object.value.as_string = const_cast<char*>(library_uri);
555
556 Dart_CObject class_object;
557 if (klass != NULL) {
558 class_object.type = Dart_CObject_kString;
559 class_object.value.as_string = const_cast<char*>(klass);
560 } else {
561 class_object.type = Dart_CObject_kNull;
562 }
563
564 Dart_CObject is_static_object;
565 is_static_object.type = Dart_CObject_kBool;
566 is_static_object.value.as_bool = is_static;
567
568 Isolate* isolate =
569 Thread::Current() != NULL ? Thread::Current()->isolate() : NULL;
570 ASSERT(isolate != NULL);
571 Dart_CObject isolate_id;
572 isolate_id.type = Dart_CObject_kInt64;
573 isolate_id.value.as_int64 =
574 isolate != NULL ? static_cast<int64_t>(isolate->main_port()) : 0;
575
576 IsolateGroupSource* source = Isolate::Current()->source();
577 intptr_t num_dills = 0;
578 if (source->kernel_buffer != nullptr) {
579 num_dills++;
580 }
581 if (source->script_kernel_buffer != nullptr) {
582 num_dills++;
583 }
584 Array& loaded_blobs = Array::Handle();
585 if (source->loaded_blobs_ != nullptr) {
586 loaded_blobs = source->loaded_blobs_;
587 WeakProperty& weak_property = WeakProperty::Handle();
588 for (intptr_t i = 0; i < loaded_blobs.Length(); i++) {
589 weak_property ^= loaded_blobs.At(i);
590 if (weak_property.key() != ExternalTypedData::null()) {
591 num_dills++;
592 }
593 }
594 }
595
596 Dart_CObject dills_object;
597 dills_object.type = Dart_CObject_kArray;
598 dills_object.value.as_array.length = num_dills;
599
600 Dart_CObject** dills_array = new Dart_CObject*[num_dills];
601 intptr_t dill_num = 0;
602 dill_num = setDillData(dills_array, dill_num, source->kernel_buffer,
603 source->kernel_buffer_size);
604 dill_num = setDillData(dills_array, dill_num, source->script_kernel_buffer,
605 source->script_kernel_size);
606 if (!loaded_blobs.IsNull()) {
607 WeakProperty& weak_property = WeakProperty::Handle();
608 for (intptr_t i = 0; i < loaded_blobs.Length(); i++) {
609 weak_property ^= loaded_blobs.At(i);
610 if (weak_property.key() != ExternalTypedData::null()) {
611 ExternalTypedData& externalTypedData = ExternalTypedData::Handle(
612 thread->zone(), ExternalTypedData::RawCast(weak_property.key()));
613 NoSafepointScope no_safepoint(thread);
614 const uint8_t* data = const_cast<uint8_t*>(
615 reinterpret_cast<uint8_t*>(externalTypedData.DataAddr(0)));
616 dill_num = setDillData(dills_array, dill_num, data,
617 externalTypedData.Length());
618 }
619 }
620 }
621 dills_object.value.as_array.values = dills_array;
622
623 Dart_CObject num_blob_loads;
624 num_blob_loads.type = Dart_CObject_kInt64;
625 num_blob_loads.value.as_int64 = source->num_blob_loads_;
626
627 Dart_CObject suppress_warnings;
628 suppress_warnings.type = Dart_CObject_kBool;
629 suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings;
630
631 Dart_CObject enable_asserts;
632 enable_asserts.type = Dart_CObject_kBool;
633 enable_asserts.value.as_bool =
634 isolate != NULL ? isolate->asserts() : FLAG_enable_asserts;
635
636 intptr_t num_experimental_flags = experimental_flags->length();
637 Dart_CObject** experimental_flags_array =
638 new Dart_CObject*[num_experimental_flags];
639 for (intptr_t i = 0; i < num_experimental_flags; ++i) {
640 experimental_flags_array[i] = new Dart_CObject;
641 experimental_flags_array[i]->type = Dart_CObject_kString;
642 experimental_flags_array[i]->value.as_string = (*experimental_flags)[i];
643 }
644 Dart_CObject experimental_flags_object;
645 experimental_flags_object.type = Dart_CObject_kArray;
646 experimental_flags_object.value.as_array.values = experimental_flags_array;
647 experimental_flags_object.value.as_array.length = num_experimental_flags;
648
649 Dart_CObject bytecode;
650 bytecode.type = Dart_CObject_kBool;
651 bytecode.value.as_bool =
652 FLAG_enable_interpreter || FLAG_use_bytecode_compiler;
653
654 Dart_CObject message;
655 message.type = Dart_CObject_kArray;
656 Dart_CObject* message_arr[] = {&tag,
657 &send_port,
658 &isolate_id,
659 &dart_platform_kernel,
660 &expression_object,
661 &definitions_object,
662 &type_definitions_object,
663 &library_uri_object,
664 &class_object,
665 &is_static_object,
666 &dills_object,
667 &num_blob_loads,
668 &suppress_warnings,
669 &enable_asserts,
670 &experimental_flags_object,
671 &bytecode};
672 message.value.as_array.values = message_arr;
673 message.value.as_array.length = ARRAY_SIZE(message_arr);
674
675 {
676 TransitionVMToNative transition(thread);
677
678 // Send the message.
679 Dart_PostCObject(kernel_port, &message);
680
681 // Wait for reply to arrive.
682 VMTagScope tagScope(thread, VMTag::kLoadWaitTagId);
683 MonitorLocker ml(&monitor_);
684 while (result_.status == Dart_KernelCompilationStatus_Unknown) {
685 ml.Wait();
686 }
687 }
688
689 for (intptr_t i = 0; i < num_definitions; ++i) {
690 delete definitions_array[i];
691 }
692 delete[] definitions_array;
693
694 for (intptr_t i = 0; i < num_type_definitions; ++i) {
695 delete type_definitions_array[i];
696 }
697 delete[] type_definitions_array;
698
699 for (intptr_t i = 0; i < num_dills; ++i) {
700 delete dills_array[i];
701 }
702 delete[] dills_array;
703
704 for (intptr_t i = 0; i < num_experimental_flags; ++i) {
705 delete experimental_flags_array[i];
706 }
707 delete[] experimental_flags_array;
708
709 return result_;
710 }
711
712 Dart_KernelCompilationResult SendAndWaitForResponse(
713 int request_tag,
714 Dart_Port kernel_port,
715 const char* script_uri,
716 const uint8_t* platform_kernel,
717 intptr_t platform_kernel_size,
718 int source_files_count,
719 Dart_SourceFile source_files[],
720 bool incremental_compile,
721 const char* package_config,
722 const char* multiroot_filepaths,
723 const char* multiroot_scheme,
724 const MallocGrowableArray<char*>* experimental_flags,
725 const char* original_working_directory) {
726 // Build the message for the Kernel isolate.
727 // tag is used to specify which operation the frontend should perform.
728 Dart_CObject tag;
729 tag.type = Dart_CObject_kInt32;
730 tag.value.as_int32 = request_tag;
731
732 Dart_CObject send_port;
733 send_port.type = Dart_CObject_kSendPort;
734 send_port.value.as_send_port.id = port_;
735 send_port.value.as_send_port.origin_id = ILLEGAL_PORT;
736
737 Dart_CObject uri;
738 if (script_uri != NULL) {
739 uri.type = Dart_CObject_kString;
740 uri.value.as_string = const_cast<char*>(script_uri);
741 } else {
742 uri.type = Dart_CObject_kNull;
743 }
744
745 Dart_CObject dart_platform_kernel;
746 if (platform_kernel != NULL) {
747 dart_platform_kernel.type = Dart_CObject_kExternalTypedData;
748 dart_platform_kernel.value.as_external_typed_data.type =
749 Dart_TypedData_kUint8;
750 dart_platform_kernel.value.as_external_typed_data.length =
751 platform_kernel_size;
752 dart_platform_kernel.value.as_external_typed_data.data =
753 const_cast<uint8_t*>(platform_kernel);
754 dart_platform_kernel.value.as_external_typed_data.peer =
755 const_cast<uint8_t*>(platform_kernel);
756 dart_platform_kernel.value.as_external_typed_data.callback =
757 PassThroughFinalizer;
758 } else {
759 // If NULL, the kernel service looks up the platform dill file
760 // next to the executable.
761 dart_platform_kernel.type = Dart_CObject_kNull;
762 }
763
764 Dart_CObject dart_incremental;
765 dart_incremental.type = Dart_CObject_kBool;
766 dart_incremental.value.as_bool = incremental_compile;
767
768 // TODO(aam): Assert that isolate exists once we move CompileAndReadScript
769 // compilation logic out of CreateIsolateAndSetupHelper and into
770 // IsolateSetupHelper in main.cc.
771 Isolate* isolate =
772 Thread::Current() != NULL ? Thread::Current()->isolate() : NULL;
773 if (incremental_compile) {
774 ASSERT(isolate != NULL);
775 }
776 Dart_CObject isolate_id;
777 isolate_id.type = Dart_CObject_kInt64;
778 isolate_id.value.as_int64 =
779 isolate != NULL ? static_cast<int64_t>(isolate->main_port()) : 0;
780
781 Dart_CObject message;
782 message.type = Dart_CObject_kArray;
783
784 Dart_CObject files = BuildFilesPairs(source_files_count, source_files);
785
786 Dart_CObject suppress_warnings;
787 suppress_warnings.type = Dart_CObject_kBool;
788 suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings;
789
790 Dart_CObject enable_asserts;
791 enable_asserts.type = Dart_CObject_kBool;
792 enable_asserts.value.as_bool =
793 isolate != NULL ? isolate->asserts() : FLAG_enable_asserts;
794
795 Dart_CObject null_safety;
796 null_safety.type = Dart_CObject_kInt32;
797 null_safety.value.as_int32 =
798 (isolate != NULL) ? (isolate->null_safety() ? kNullSafetyOptionStrong
799 : kNullSafetyOptionWeak)
800 : FLAG_sound_null_safety;
801
802 intptr_t num_experimental_flags = experimental_flags->length();
803 Dart_CObject** experimental_flags_array =
804 new Dart_CObject*[num_experimental_flags];
805 for (intptr_t i = 0; i < num_experimental_flags; ++i) {
806 experimental_flags_array[i] = new Dart_CObject;
807 experimental_flags_array[i]->type = Dart_CObject_kString;
808 experimental_flags_array[i]->value.as_string = (*experimental_flags)[i];
809 }
810 Dart_CObject experimental_flags_object;
811 experimental_flags_object.type = Dart_CObject_kArray;
812 experimental_flags_object.value.as_array.values = experimental_flags_array;
813 experimental_flags_object.value.as_array.length = num_experimental_flags;
814
815 Dart_CObject bytecode;
816 bytecode.type = Dart_CObject_kBool;
817 bytecode.value.as_bool =
818 FLAG_enable_interpreter || FLAG_use_bytecode_compiler;
819
820 Dart_CObject package_config_uri;
821 if (package_config != NULL) {
822 package_config_uri.type = Dart_CObject_kString;
823 package_config_uri.value.as_string = const_cast<char*>(package_config);
824 } else {
825 package_config_uri.type = Dart_CObject_kNull;
826 }
827
828 Dart_CObject multiroot_filepaths_object;
829 {
830 const char* filepaths = multiroot_filepaths != NULL
831 ? multiroot_filepaths
832 : FLAG_kernel_multiroot_filepaths;
833 if (filepaths != NULL) {
834 multiroot_filepaths_object.type = Dart_CObject_kString;
835 multiroot_filepaths_object.value.as_string =
836 const_cast<char*>(filepaths);
837 } else {
838 multiroot_filepaths_object.type = Dart_CObject_kNull;
839 }
840 }
841
842 Dart_CObject multiroot_scheme_object;
843 {
844 const char* scheme = multiroot_scheme != NULL
845 ? multiroot_scheme
846 : FLAG_kernel_multiroot_scheme;
847 if (scheme != NULL) {
848 multiroot_scheme_object.type = Dart_CObject_kString;
849 multiroot_scheme_object.value.as_string = const_cast<char*>(scheme);
850 } else {
851 multiroot_scheme_object.type = Dart_CObject_kNull;
852 }
853 }
854
855 Dart_CObject original_working_directory_object;
856 {
857 if (original_working_directory != NULL) {
858 original_working_directory_object.type = Dart_CObject_kString;
859 original_working_directory_object.value.as_string =
860 const_cast<char*>(original_working_directory);
861 } else {
862 original_working_directory_object.type = Dart_CObject_kNull;
863 }
864 }
865
866 Dart_CObject* message_arr[] = {&tag,
867 &send_port,
868 &uri,
869 &dart_platform_kernel,
870 &dart_incremental,
871 &null_safety,
872 &isolate_id,
873 &files,
874 &suppress_warnings,
875 &enable_asserts,
876 &experimental_flags_object,
877 &bytecode,
878 &package_config_uri,
879 &multiroot_filepaths_object,
880 &multiroot_scheme_object,
881 &original_working_directory_object};
882 message.value.as_array.values = message_arr;
883 message.value.as_array.length = ARRAY_SIZE(message_arr);
884 // Send the message.
885 Dart_PostCObject(kernel_port, &message);
886
887 ReleaseFilesPairs(files);
888
889 // Wait for reply to arrive.
890 VMTagScope tagScope(Thread::Current(), VMTag::kLoadWaitTagId);
891 MonitorLocker ml(&monitor_);
892 while (result_.status == Dart_KernelCompilationStatus_Unknown) {
893 ml.Wait();
894 }
895
896 for (intptr_t i = 0; i < num_experimental_flags; ++i) {
897 delete experimental_flags_array[i];
898 }
899 delete[] experimental_flags_array;
900
901 return result_;
902 }
903
904 private:
905 void LoadKernelFromResponse(Dart_CObject* response) {
906 ASSERT((response->type == Dart_CObject_kTypedData) ||
907 (response->type == Dart_CObject_kBool) ||
908 (response->type == Dart_CObject_kNull));
909
910 if (response->type == Dart_CObject_kNull) {
911 return;
912 }
913 if (response->type == Dart_CObject_kBool) {
914 result_.null_safety = response->value.as_bool;
915 return;
916 }
917
918 ASSERT(response->value.as_typed_data.type == Dart_TypedData_kUint8);
919 result_.kernel_size = response->value.as_typed_data.length;
920 result_.kernel = static_cast<uint8_t*>(malloc(result_.kernel_size));
921 memmove(result_.kernel, response->value.as_typed_data.values,
922 result_.kernel_size);
923 }
924
925 // Possible responses from the Kernel isolate:
926 //
927 // [Ok, Uint8List KernelBinary]
928 // [Error, String error, Uint8List KernelBinary]
929 // [Crash, String error]
930 //
931 void HandleResponseImpl(Dart_CObject* message) {
932 ASSERT(message->type == Dart_CObject_kArray);
933 ASSERT(message->value.as_array.length >= 1);
934
935 Dart_CObject** response = message->value.as_array.values;
936
937 MonitorLocker ml(&monitor_);
938
939 ASSERT(response[0]->type == Dart_CObject_kInt32);
940 result_.status = static_cast<Dart_KernelCompilationStatus>(
941 message->value.as_array.values[0]->value.as_int32);
942
943 if (result_.status == Dart_KernelCompilationStatus_Ok) {
944 LoadKernelFromResponse(response[1]);
945 } else {
946 if (result_.status == Dart_KernelCompilationStatus_Error) {
947 LoadKernelFromResponse(response[2]);
948 }
949 // This is an error.
950 ASSERT(response[1]->type == Dart_CObject_kString);
951 result_.error = Utils::StrDup(response[1]->value.as_string);
952 }
953 ml.Notify();
954 }
955
956 static void HandleResponse(Dart_Port port, Dart_CObject* message) {
957 MonitorLocker locker(requests_monitor_);
958 KernelCompilationRequest* rq = FindRequestLocked(port);
959 if (rq == NULL) {
960 return;
961 }
962 rq->HandleResponseImpl(message);
963 }
964
965 static void RegisterRequest(KernelCompilationRequest* rq) {
966 MonitorLocker locker(requests_monitor_);
967 rq->next_ = requests_;
968 if (requests_ != NULL) {
969 requests_->prev_ = rq;
970 }
971 requests_ = rq;
972 }
973
974 static void UnregisterRequest(KernelCompilationRequest* rq) {
975 MonitorLocker locker(requests_monitor_);
976 if (rq->next_ != NULL) {
977 rq->next_->prev_ = rq->prev_;
978 }
979 if (rq->prev_ != NULL) {
980 rq->prev_->next_ = rq->next_;
981 } else {
982 requests_ = rq->next_;
983 }
984 }
985
986 // Note: Caller must hold requests_monitor_.
987 static KernelCompilationRequest* FindRequestLocked(Dart_Port port) {
988 for (KernelCompilationRequest* rq = requests_; rq != NULL; rq = rq->next_) {
989 if (rq->port_ == port) {
990 return rq;
991 }
992 }
993 return NULL;
994 }
995
996 // This monitor must be held whenever linked list of requests is accessed.
997 static Monitor* requests_monitor_;
998
999 // Linked list of all active requests. Used to find a request by port number.
1000 // Guarded by requests_monitor_ lock.
1001 static KernelCompilationRequest* requests_;
1002
1003 Monitor monitor_;
1004 Dart_Port port_;
1005
1006 // Linked list of active requests. Guarded by requests_monitor_ lock.
1007 KernelCompilationRequest* next_;
1008 KernelCompilationRequest* prev_;
1009
1010 Dart_KernelCompilationResult result_ = {};
1011};
1012
1013Monitor* KernelCompilationRequest::requests_monitor_ = new Monitor();
1014KernelCompilationRequest* KernelCompilationRequest::requests_ = NULL;
1015
1016Dart_KernelCompilationResult KernelIsolate::CompileToKernel(
1017 const char* script_uri,
1018 const uint8_t* platform_kernel,
1019 intptr_t platform_kernel_size,
1020 int source_file_count,
1021 Dart_SourceFile source_files[],
1022 bool incremental_compile,
1023 const char* package_config,
1024 const char* multiroot_filepaths,
1025 const char* multiroot_scheme) {
1026 // Start the kernel Isolate if it is not already running.
1027 if (!Start()) {
1028 Dart_KernelCompilationResult result = {};
1029 result.status = Dart_KernelCompilationStatus_Unknown;
1030 result.error = Utils::StrDup("Error while starting Kernel isolate task");
1031 return result;
1032 }
1033
1034 // This must be the main script to be loaded. Wait for Kernel isolate
1035 // to finish initialization.
1036 Dart_Port kernel_port = WaitForKernelPort();
1037 if (kernel_port == ILLEGAL_PORT) {
1038 Dart_KernelCompilationResult result = {};
1039 result.status = Dart_KernelCompilationStatus_Unknown;
1040 result.error = Utils::StrDup("Error while initializing Kernel isolate");
1041 return result;
1042 }
1043
1044 KernelCompilationRequest request;
1045 return request.SendAndWaitForResponse(
1046 kCompileTag, kernel_port, script_uri, platform_kernel,
1047 platform_kernel_size, source_file_count, source_files,
1048 incremental_compile, package_config, multiroot_filepaths,
1049 multiroot_scheme, experimental_flags_, NULL);
1050}
1051
1052bool KernelIsolate::DetectNullSafety(const char* script_uri,
1053 const char* package_config,
1054 const char* original_working_directory) {
1055 // Start the kernel Isolate if it is not already running.
1056 if (!Start()) {
1057 Dart_KernelCompilationResult result = {};
1058 result.status = Dart_KernelCompilationStatus_Unknown;
1059 result.error = Utils::StrDup("Error while starting Kernel isolate task");
1060 return false;
1061 }
1062 // Wait for Kernel isolate to finish initialization.
1063 Dart_Port kernel_port = WaitForKernelPort();
1064 if (kernel_port == ILLEGAL_PORT) {
1065 Dart_KernelCompilationResult result = {};
1066 result.status = Dart_KernelCompilationStatus_Unknown;
1067 result.error = Utils::StrDup("Error while initializing Kernel isolate");
1068 return false;
1069 }
1070 KernelCompilationRequest request;
1071 Dart_KernelCompilationResult result = request.SendAndWaitForResponse(
1072 kDetectNullabilityTag, kernel_port, script_uri, nullptr, -1, 0, nullptr,
1073 false, package_config, nullptr, nullptr, experimental_flags_,
1074 original_working_directory);
1075 return result.null_safety;
1076}
1077
1078Dart_KernelCompilationResult KernelIsolate::ListDependencies() {
1079 Dart_Port kernel_port = WaitForKernelPort();
1080 if (kernel_port == ILLEGAL_PORT) {
1081 Dart_KernelCompilationResult result = {};
1082 result.status = Dart_KernelCompilationStatus_Unknown;
1083 result.error = Utils::StrDup("Error while initializing Kernel isolate");
1084 return result;
1085 }
1086
1087 KernelCompilationRequest request;
1088 return request.SendAndWaitForResponse(kListDependenciesTag, kernel_port, NULL,
1089 NULL, 0, 0, NULL, false, NULL, NULL,
1090 NULL, experimental_flags_, NULL);
1091}
1092
1093Dart_KernelCompilationResult KernelIsolate::AcceptCompilation() {
1094 // This must be the main script to be loaded. Wait for Kernel isolate
1095 // to finish initialization.
1096 Dart_Port kernel_port = WaitForKernelPort();
1097 if (kernel_port == ILLEGAL_PORT) {
1098 Dart_KernelCompilationResult result = {};
1099 result.status = Dart_KernelCompilationStatus_Unknown;
1100 result.error = Utils::StrDup("Error while initializing Kernel isolate");
1101 return result;
1102 }
1103
1104 KernelCompilationRequest request;
1105 return request.SendAndWaitForResponse(kAcceptTag, kernel_port, NULL, NULL, 0,
1106 0, NULL, true, NULL, NULL, NULL,
1107 experimental_flags_, NULL);
1108}
1109
1110Dart_KernelCompilationResult KernelIsolate::CompileExpressionToKernel(
1111 const uint8_t* platform_kernel,
1112 intptr_t platform_kernel_size,
1113 const char* expression,
1114 const Array& definitions,
1115 const Array& type_definitions,
1116 const char* library_url,
1117 const char* klass,
1118 bool is_static) {
1119 Dart_Port kernel_port = WaitForKernelPort();
1120 if (kernel_port == ILLEGAL_PORT) {
1121 Dart_KernelCompilationResult result = {};
1122 result.status = Dart_KernelCompilationStatus_Unknown;
1123 result.error = Utils::StrDup("Error while initializing Kernel isolate");
1124 return result;
1125 }
1126
1127 TransitionVMToNative transition(Thread::Current());
1128 KernelCompilationRequest request;
1129 ASSERT(is_static || (klass != nullptr));
1130 return request.SendAndWaitForResponse(
1131 kernel_port, platform_kernel, platform_kernel_size, expression,
1132 definitions, type_definitions, library_url, klass, is_static,
1133 experimental_flags_);
1134}
1135
1136Dart_KernelCompilationResult KernelIsolate::UpdateInMemorySources(
1137 int source_files_count,
1138 Dart_SourceFile source_files[]) {
1139 // This must be the main script to be loaded. Wait for Kernel isolate
1140 // to finish initialization.
1141 Dart_Port kernel_port = WaitForKernelPort();
1142 if (kernel_port == ILLEGAL_PORT) {
1143 Dart_KernelCompilationResult result = {};
1144 result.status = Dart_KernelCompilationStatus_Unknown;
1145 result.error = Utils::StrDup("Error while initializing Kernel isolate");
1146 return result;
1147 }
1148
1149 KernelCompilationRequest request;
1150 return request.SendAndWaitForResponse(
1151 kUpdateSourcesTag, kernel_port, NULL, NULL, 0, source_files_count,
1152 source_files, true, NULL, NULL, NULL, experimental_flags_, NULL);
1153}
1154
1155void KernelIsolate::NotifyAboutIsolateShutdown(const Isolate* isolate) {
1156 if (!KernelIsolate::IsRunning()) {
1157 return;
1158 }
1159 Dart_Port kernel_port = WaitForKernelPort();
1160 if (kernel_port == ILLEGAL_PORT) {
1161 return;
1162 }
1163
1164 Dart_CObject tag;
1165 tag.type = Dart_CObject_kInt32;
1166 tag.value.as_int32 = KernelIsolate::kNotifyIsolateShutdown;
1167
1168 Dart_CObject isolate_id;
1169 isolate_id.type = Dart_CObject_kInt64;
1170 isolate_id.value.as_int64 =
1171 isolate != NULL ? static_cast<int64_t>(isolate->main_port()) : 0;
1172
1173 Dart_CObject message;
1174 message.type = Dart_CObject_kArray;
1175 Dart_CObject* message_arr[] = {&tag, &isolate_id};
1176 message.value.as_array.values = message_arr;
1177 message.value.as_array.length = ARRAY_SIZE(message_arr);
1178 // Send the message.
1179 Dart_PostCObject(kernel_port, &message);
1180}
1181
1182} // namespace dart
1183
1184#endif // !defined(DART_PRECOMPILED_RUNTIME)
1185