Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(639)

Side by Side Diff: runtime/bin/loader.cc

Issue 1998963003: Rework standalone to use a synchronous loader that does not invoke Dart code (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
6 #include "bin/loader.h"
7
8 #include "bin/builtin.h"
9 #include "bin/dartutils.h"
10 #include "bin/extensions.h"
11 #include "bin/lockers.h"
12
13 namespace dart {
14 namespace bin {
15
16 // Development flag.
17 static bool trace_loader = false;
18
19 Loader::Loader(IsolateData* isolate_data)
20 : port_(ILLEGAL_PORT),
21 isolate_data_(isolate_data),
22 error_(Dart_Null()),
23 monitor_(NULL),
24 pending_operations_(0),
25 results_(NULL),
26 results_length_(0),
27 results_capacity_(0) {
28 monitor_ = new Monitor();
29 ASSERT(isolate_data_ != NULL);
30 port_ = Dart_NewNativePort("Loader",
31 Loader::NativeMessageHandler,
32 false);
33 isolate_data_->set_loader(this);
34 AddLoader(port_, isolate_data_);
35 }
36
37
38 Loader::~Loader() {
39 ASSERT(port_ != ILLEGAL_PORT);
40 RemoveLoader(port_);
41 Dart_CloseNativePort(port_);
42 port_ = ILLEGAL_PORT;
43 isolate_data_->set_loader(NULL);
44 isolate_data_ = NULL;
45 delete monitor_;
46 monitor_ = NULL;
47 for (intptr_t i = 0; i < results_length_; i++) {
48 results_[i].Cleanup();
49 }
50 free(results_);
51 results_ = NULL;
52 }
53
54
55 // Copy the contents of |message| into an |IOResult|.
56 void Loader::IOResult::Setup(Dart_CObject* message) {
57 ASSERT(message->type == Dart_CObject_kArray);
58 ASSERT(message->value.as_array.length == 4);
59 Dart_CObject* tag_message = message->value.as_array.values[0];
60 ASSERT(tag_message != NULL);
61 Dart_CObject* uri_message = message->value.as_array.values[1];
62 ASSERT(uri_message != NULL);
63 Dart_CObject* library_uri_message = message->value.as_array.values[2];
64 ASSERT(library_uri_message != NULL);
65 Dart_CObject* payload_message = message->value.as_array.values[3];
66 ASSERT(payload_message != NULL);
67
68 // Grab the tag.
69 ASSERT(tag_message->type == Dart_CObject_kInt32);
70 tag = tag_message->value.as_int32;
71
72 // Grab the uri id.
73 ASSERT(uri_message->type == Dart_CObject_kString);
74 uri = strdup(uri_message->value.as_string);
75
76 // Grab the library uri if one is present.
77 if (library_uri_message->type != Dart_CObject_kNull) {
78 ASSERT(library_uri_message->type == Dart_CObject_kString);
79 library_uri = strdup(library_uri_message->value.as_string);
80 } else {
81 library_uri = NULL;
82 }
83
84 // Grab the payload.
85 if (payload_message->type == Dart_CObject_kString) {
86 // Payload is an error message.
87 payload_length = strlen(payload_message->value.as_string);
88 payload =
89 reinterpret_cast<uint8_t*>(strdup(payload_message->value.as_string));
90 } else {
91 // Payload is the contents of a file.
92 ASSERT(payload_message->type == Dart_CObject_kTypedData);
93 ASSERT(payload_message->value.as_typed_data.type == Dart_TypedData_kUint8);
94 payload_length = payload_message->value.as_typed_data.length;
95 payload = reinterpret_cast<uint8_t*>(malloc(payload_length));
96 memmove(payload,
97 payload_message->value.as_typed_data.values,
98 payload_length);
99 }
100 }
101
102
103 void Loader::IOResult::Cleanup() {
104 free(uri);
105 free(library_uri);
106 free(payload);
107 }
108
109
110 // Send the Loader Initialization message to the service isolate. This
111 // message is sent the first time a loader is constructed for an isolate and
112 // seeds the service isolate with some initial state about this isolate.
113 void Loader::Init(const char* package_root,
114 const char* packages_file,
115 const char* working_directory) {
116 // This port delivers loading messages to the service isolate.
117 Dart_Port loader_port = Builtin::LoadPort();
118 ASSERT(loader_port != ILLEGAL_PORT);
119
120 // Keep in sync with loader.dart.
121 const intptr_t _Dart_kInitLoader = 4;
122
123 Dart_Handle request = Dart_NewList(7);
124 Dart_ListSetAt(request, 0, trace_loader ? Dart_True() : Dart_False());
125 Dart_ListSetAt(request, 1, Dart_NewInteger(Dart_GetMainPortId()));
126 Dart_ListSetAt(request, 2, Dart_NewInteger(_Dart_kInitLoader));
127 Dart_ListSetAt(request, 3, Dart_NewSendPort(port_));
128 Dart_ListSetAt(request, 4,
129 (package_root == NULL) ? Dart_Null() :
130 Dart_NewStringFromCString(package_root));
131 Dart_ListSetAt(request, 5,
132 (packages_file == NULL) ? Dart_Null() :
133 Dart_NewStringFromCString(packages_file));
134 Dart_ListSetAt(request, 6,
135 Dart_NewStringFromCString(working_directory));
136
137 bool success = Dart_Post(loader_port, request);
138 ASSERT(success);
139 }
140
141
142 // Forward a request from the tag handler to the service isolate.
143 void Loader::SendRequest(Dart_LibraryTag tag,
144 Dart_Handle url,
145 Dart_Handle library_url) {
146 // This port delivers loading messages to the service isolate.
147 Dart_Port loader_port = Builtin::LoadPort();
148 ASSERT(loader_port != ILLEGAL_PORT);
149
150 Dart_Handle request = Dart_NewList(6);
151 Dart_ListSetAt(request, 0, trace_loader ? Dart_True() : Dart_False());
152 Dart_ListSetAt(request, 1, Dart_NewInteger(Dart_GetMainPortId()));
153 Dart_ListSetAt(request, 2, Dart_NewInteger(tag));
154 Dart_ListSetAt(request, 3, Dart_NewSendPort(port_));
155
156 Dart_ListSetAt(request, 4, url);
157 Dart_ListSetAt(request, 5, library_url);
158
159 if (Dart_Post(loader_port, request)) {
160 MonitorLocker ml(monitor_);
161 pending_operations_++;
162 }
163 }
164
165
166 void Loader::QueueMessage(Dart_CObject* message) {
167 MonitorLocker ml(monitor_);
168 if (results_length_ == results_capacity_) {
169 // Grow to an initial capacity or double in size.
170 results_capacity_ = (results_capacity_ == 0) ? 4 : results_capacity_ * 2;
171 results_ =
172 reinterpret_cast<IOResult*>(
173 realloc(results_,
174 sizeof(IOResult) * results_capacity_));
175 ASSERT(results_ != NULL);
176 }
177 ASSERT(results_ != NULL);
178 ASSERT(results_length_ < results_capacity_);
179 results_[results_length_].Setup(message);
180 results_length_++;
181 ml.Notify();
182 }
183
184
185 void Loader::BlockUntilComplete() {
186 MonitorLocker ml(monitor_);
187
188 while (true) {
189 if (!ProcessQueueLocked()) {
turnidge 2016/06/03 17:50:25 Maybe add some small comments here in each case...
Cutch 2016/06/03 22:07:32 Done.
190 break;
191 }
192 if (pending_operations_ == 0) {
193 break;
194 }
195 ml.Wait();
196 }
197 }
198
199
200 bool Loader::ProcessResultLocked(Loader::IOResult* result) {
201 // A negative result tag indicates a loading error occurred in the service
202 // isolate. The payload is a C string of the error message.
203 if (result->tag < 0) {
204 error_ =
205 Dart_NewUnhandledExceptionError(
206 Dart_NewStringFromUTF8(result->payload,
207 result->payload_length));
208
209 return false;
210 }
211
212 // We have to copy everything we care about out of |result| because after
213 // dropping the lock below |result| may no longer valid.
214 Dart_Handle uri =
215 Dart_NewStringFromCString(reinterpret_cast<char*>(result->uri));
216 Dart_Handle library_uri = Dart_Null();
217 if (result->library_uri != NULL) {
218 library_uri =
219 Dart_NewStringFromCString(reinterpret_cast<char*>(result->library_uri));
220 }
221 Dart_Handle source =
222 Dart_NewStringFromUTF8(result->payload,
223 result->payload_length);
224 intptr_t tag = result->tag;
225
226 // No touching.
227 result = NULL;
228
229 // We must drop the lock here because the tag handler may be recursively
230 // invoked and it will attempt to acquire the lock to queue more work.
231 monitor_->Exit();
232
233 Dart_Handle dart_result = Dart_Null();
234
235
236 switch (tag) {
237 case Dart_kImportTag:
238 dart_result = Dart_LoadLibrary(uri, source, 0, 0);
239 break;
240 case Dart_kSourceTag: {
241 ASSERT(library_uri != Dart_Null());
242 Dart_Handle library = Dart_LookupLibrary(library_uri);
243 ASSERT(!Dart_IsError(library));
244 dart_result = Dart_LoadSource(library, uri, source, 0, 0);
245 }
246 break;
247 case Dart_kScriptTag:
248 dart_result = Dart_LoadScript(uri, source, 0, 0);
249 break;
250 default:
251 UNREACHABLE();
252 }
253
254 // Re-acquire the lock before decrementing pending operations.
turnidge 2016/06/03 17:50:25 Confusing comment...
Cutch 2016/06/03 22:07:32 Done.
255 monitor_->Enter();
256 if (Dart_IsError(dart_result)) {
257 error_ = dart_result;
258 return false;
259 }
260
261 return true;
262 }
263
264
265 bool Loader::ProcessQueueLocked() {
266 bool hit_error = false;
267 for (intptr_t i = 0; i < results_length_; i++) {
268 if (!hit_error) {
269 hit_error = !ProcessResultLocked(&results_[i]);
270 }
271 pending_operations_--;
272 ASSERT(pending_operations_ >= 0);
273 results_[i].Cleanup();
274 }
275 results_length_ = 0;
276 return !hit_error;
277 }
278
279
280 static bool IsWindowsHost() {
281 #if defined(TARGET_OS_WINDOWS)
282 return true;
283 #else // defined(TARGET_OS_WINDOWS)
284 return false;
285 #endif // defined(TARGET_OS_WINDOWS)
286 }
287
288
289 Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag,
290 Dart_Handle library,
291 Dart_Handle url) {
turnidge 2016/06/03 17:50:25 Merge this by hand with my new version that I just
Cutch 2016/06/03 22:07:32 Done.
292 const char* url_string = NULL;
293 Dart_Handle result = Dart_StringToCString(url, &url_string);
294 if (Dart_IsError(result)) {
295 return result;
296 }
297
298 // Special case for handling dart: imports and parts.
299 if (tag != Dart_kScriptTag) {
300 // Grab the library's url.
301 Dart_Handle library_url = Dart_LibraryUrl(library);
302 const char* library_url_string = NULL;
303 result = Dart_StringToCString(library_url, &library_url_string);
304 if (Dart_IsError(result)) {
305 return result;
306 }
307
308 bool is_dart_scheme_url = DartUtils::IsDartSchemeURL(url_string);
309 bool is_dart_library = DartUtils::IsDartSchemeURL(library_url_string);
310
311 if (is_dart_scheme_url || is_dart_library) {
312 return DartColonLibraryTagHandler(tag,
313 library,
314 url,
315 library_url_string,
316 url_string);
317 }
318 }
319
320 if (tag == Dart_kCanonicalizeUrl) {
321 // TODO(johnmccutchan): Use turnidge's url canonicalization.
322 return DartUtils::ResolveUri(Dart_LibraryUrl(library), url);
323 }
324
325 if (DartUtils::IsDartExtensionSchemeURL(url_string)) {
326 // Load a native code shared library to use in a native extension
327 if (tag != Dart_kImportTag) {
328 return DartUtils::NewError("Dart extensions must use import: '%s'",
329 url_string);
330 }
331 Dart_Handle library_url = Dart_LibraryUrl(library);
332 Dart_Handle library_file_path = DartUtils::LibraryFilePath(library_url);
333 const char* lib_path_str = NULL;
334 Dart_StringToCString(library_file_path, &lib_path_str);
335 const char* extension_path = DartUtils::RemoveScheme(url_string);
336 if (strchr(extension_path, '/') != NULL ||
337 (IsWindowsHost() && strchr(extension_path, '\\') != NULL)) {
338 return DartUtils::NewError(
339 "Relative paths for dart extensions are not supported: '%s'",
340 extension_path);
341 }
342 return Extensions::LoadExtension(lib_path_str,
343 extension_path,
344 library);
345 }
346
347 // Grab this isolate's loader.
348 IsolateData* isolate_data =
349 reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
350 ASSERT(isolate_data != NULL);
351 // The first invocation of the tag handler will block until any nested
352 // calls complete.
353 bool blocking_call = false;
354 Loader* loader = NULL;
355 if (!isolate_data->HasLoader()) {
356 // Mark that we are a blocking call.
turnidge 2016/06/03 17:50:25 This comment could be bigger. This is subtle
Cutch 2016/06/03 22:07:32 Done.
357 blocking_call = true;
358 // Setup the loader. The constructor does a bunch of leg work.
359 loader = new Loader(isolate_data);
360 loader->Init(isolate_data->package_root,
361 isolate_data->packages_file,
362 DartUtils::original_working_directory);
363 } else {
364 // Use the existing loader.
365 loader = isolate_data->loader();
366 }
367 ASSERT(loader != NULL);
368 ASSERT(isolate_data->HasLoader());
369
370 loader->SendRequest(tag,
371 url,
372 (library != Dart_Null()) ?
373 Dart_LibraryUrl(library) : Dart_Null());
374
375 if (blocking_call) {
376 loader->BlockUntilComplete();
377 // Remember the error (if any).
378 Dart_Handle error = loader->error();
379 // Destroy the loader. The destructor does a bunch of leg work.
380 delete loader;
381 // An error occurred during loading.
382 if (Dart_IsError(error)) {
383 return error;
384 }
385 // Finalize loading.
386 error = Dart_FinalizeLoading(true);
387 if (Dart_IsError(error)) {
388 return error;
389 }
390 }
391 return Dart_Null();
392 }
393
394
395 Dart_Handle Loader::DartColonLibraryTagHandler(Dart_LibraryTag tag,
396 Dart_Handle library,
397 Dart_Handle url,
398 const char* library_url_string,
399 const char* url_string) {
400 // Handle canonicalization, 'import' and 'part' of 'dart:' libraries.
401 if (tag == Dart_kCanonicalizeUrl) {
402 // These will be handled internally.
403 return url;
404 } else if (tag == Dart_kImportTag) {
405 Builtin::BuiltinLibraryId id = Builtin::FindId(url_string);
406 if (id == Builtin::kInvalidLibrary) {
407 return DartUtils::NewError("The built-in library '%s' is not available"
408 " on the stand-alone VM.\n", url_string);
409 }
410 return Builtin::LoadLibrary(url, id);
411 } else {
412 ASSERT(tag == Dart_kSourceTag);
413 Builtin::BuiltinLibraryId id = Builtin::FindId(library_url_string);
414 if (id == Builtin::kInvalidLibrary) {
415 return DartUtils::NewError("The built-in library '%s' is not available"
416 " on the stand-alone VM. Trying to load"
417 " '%s'.\n", library_url_string, url_string);
418 }
419 // Prepend the library URI to form a unique script URI for the part.
420 intptr_t len = snprintf(NULL, 0, "%s/%s", library_url_string, url_string);
421 char* part_uri = reinterpret_cast<char*>(malloc(len + 1));
422 snprintf(part_uri, len + 1, "%s/%s", library_url_string, url_string);
423 Dart_Handle part_uri_obj = DartUtils::NewString(part_uri);
424 free(part_uri);
425 return Dart_LoadSource(library,
426 part_uri_obj,
427 Builtin::PartSource(id, url_string), 0, 0);
428 }
429 // All cases should have been handled above.
430 UNREACHABLE();
431 }
432
433
434 Mutex Loader::loader_infos_lock_;
435 Loader::LoaderInfo* Loader::loader_infos_ = NULL;
436 intptr_t Loader::loader_infos_length_ = 0;
437 intptr_t Loader::loader_infos_capacity_ = 0;
438
439
440 void Loader::AddLoader(Dart_Port port, IsolateData* isolate_data) {
turnidge 2016/06/03 17:50:25 Maybe a comment about what this does.
Cutch 2016/06/03 22:07:32 Done.
441 ASSERT(LoaderFor(port) == NULL);
442 if (loader_infos_length_ == loader_infos_capacity_) {
443 // Grow to an initial capacity or double in size.
444 loader_infos_capacity_ =
445 (loader_infos_capacity_ == 0) ? 4 : loader_infos_capacity_ * 2;
446 loader_infos_ =
447 reinterpret_cast<Loader::LoaderInfo*>(
448 realloc(loader_infos_,
449 sizeof(Loader::LoaderInfo) * loader_infos_capacity_));
450 ASSERT(loader_infos_ != NULL);
451 // Initialize new entries.
452 for (intptr_t i = loader_infos_length_; i < loader_infos_capacity_; i++) {
453 loader_infos_[i].port = ILLEGAL_PORT;
454 loader_infos_[i].isolate_data = NULL;
455 }
456 }
457 ASSERT(loader_infos_length_ < loader_infos_capacity_);
458 loader_infos_[loader_infos_length_].port = port;
459 loader_infos_[loader_infos_length_].isolate_data = isolate_data;
460 loader_infos_length_++;
461 ASSERT(LoaderFor(port) != NULL);
462 }
463
464
465 void Loader::RemoveLoader(Dart_Port port) {
466 const intptr_t index = LoaderIndexFor(port);
467 ASSERT(index >= 0);
468 const intptr_t last = loader_infos_length_ - 1;
469 ASSERT(last >= 0);
470 if (index != last) {
471 // Swap with the tail.
472 loader_infos_[index] = loader_infos_[last];
473 }
474 loader_infos_length_--;
475 }
476
477
478 intptr_t Loader::LoaderIndexFor(Dart_Port port) {
479 for (intptr_t i = 0; i < loader_infos_length_; i++) {
480 if (loader_infos_[i].port == port) {
481 return i;
482 }
483 }
484 return -1;
485 }
486
487
488 Loader* Loader::LoaderFor(Dart_Port port) {
489 intptr_t index = LoaderIndexFor(port);
490 if (index < 0) {
491 return NULL;
492 }
493 return loader_infos_[index].isolate_data->loader();
494 }
495
496
497 void Loader::NativeMessageHandler(Dart_Port dest_port_id,
498 Dart_CObject* message) {
499 Loader* loader = LoaderFor(dest_port_id);
500 if (loader == NULL) {
501 return;
502 }
503 loader->QueueMessage(message);
504 }
505
506 } // namespace bin
507 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698