| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 | 5 |
| 6 #include "bin/loader.h" | 6 #include "bin/loader.h" |
| 7 | 7 |
| 8 #include "bin/builtin.h" | 8 #include "bin/builtin.h" |
| 9 #include "bin/dartutils.h" | 9 #include "bin/dartutils.h" |
| 10 #include "bin/extensions.h" | 10 #include "bin/extensions.h" |
| 11 #include "bin/lockers.h" | 11 #include "bin/lockers.h" |
| 12 #include "bin/utils.h" | 12 #include "bin/utils.h" |
| 13 | 13 |
| 14 namespace dart { | 14 namespace dart { |
| 15 namespace bin { | 15 namespace bin { |
| 16 | 16 |
| 17 // Development flag. | 17 // Development flag. |
| 18 static bool trace_loader = false; | 18 static bool trace_loader = false; |
| 19 | 19 |
| 20 Loader::Loader(IsolateData* isolate_data) | 20 Loader::Loader(IsolateData* isolate_data) |
| 21 : port_(ILLEGAL_PORT), | 21 : port_(ILLEGAL_PORT), |
| 22 isolate_data_(isolate_data), | 22 isolate_data_(isolate_data), |
| 23 error_(Dart_Null()), | 23 error_(Dart_Null()), |
| 24 monitor_(NULL), | 24 monitor_(NULL), |
| 25 pending_operations_(0), | 25 pending_operations_(0), |
| 26 results_(NULL), | 26 results_(NULL), |
| 27 results_length_(0), | 27 results_length_(0), |
| 28 results_capacity_(0) { | 28 results_capacity_(0), |
| 29 payload_(NULL), |
| 30 payload_length_(0) { |
| 29 monitor_ = new Monitor(); | 31 monitor_ = new Monitor(); |
| 30 ASSERT(isolate_data_ != NULL); | 32 ASSERT(isolate_data_ != NULL); |
| 31 port_ = Dart_NewNativePort("Loader", | 33 port_ = Dart_NewNativePort("Loader", |
| 32 Loader::NativeMessageHandler, | 34 Loader::NativeMessageHandler, |
| 33 false); | 35 false); |
| 34 isolate_data_->set_loader(this); | 36 isolate_data_->set_loader(this); |
| 35 AddLoader(port_, isolate_data_); | 37 AddLoader(port_, isolate_data_); |
| 36 } | 38 } |
| 37 | 39 |
| 38 | 40 |
| 39 Loader::~Loader() { | 41 Loader::~Loader() { |
| 40 ASSERT(port_ != ILLEGAL_PORT); | 42 ASSERT(port_ != ILLEGAL_PORT); |
| 41 // Enter the monitor while we close the Dart port. After the Dart port is | 43 // Enter the monitor while we close the Dart port. After the Dart port is |
| 42 // closed, no more results can be queued. | 44 // closed, no more results can be queued. |
| 43 monitor_->Enter(); | 45 monitor_->Enter(); |
| 44 Dart_CloseNativePort(port_); | 46 Dart_CloseNativePort(port_); |
| 45 monitor_->Exit(); | 47 monitor_->Exit(); |
| 46 RemoveLoader(port_); | 48 RemoveLoader(port_); |
| 47 port_ = ILLEGAL_PORT; | 49 port_ = ILLEGAL_PORT; |
| 48 isolate_data_->set_loader(NULL); | 50 isolate_data_->set_loader(NULL); |
| 49 isolate_data_ = NULL; | 51 isolate_data_ = NULL; |
| 50 delete monitor_; | 52 delete monitor_; |
| 51 monitor_ = NULL; | 53 monitor_ = NULL; |
| 52 for (intptr_t i = 0; i < results_length_; i++) { | 54 for (intptr_t i = 0; i < results_length_; i++) { |
| 53 results_[i].Cleanup(); | 55 results_[i].Cleanup(); |
| 54 } | 56 } |
| 55 free(results_); | 57 free(results_); |
| 56 results_ = NULL; | 58 results_ = NULL; |
| 59 payload_ = NULL; |
| 60 payload_length_ = 0; |
| 57 } | 61 } |
| 58 | 62 |
| 59 | 63 |
| 60 // Copy the contents of |message| into an |IOResult|. | 64 // Copy the contents of |message| into an |IOResult|. |
| 61 void Loader::IOResult::Setup(Dart_CObject* message) { | 65 void Loader::IOResult::Setup(Dart_CObject* message) { |
| 62 ASSERT(message->type == Dart_CObject_kArray); | 66 ASSERT(message->type == Dart_CObject_kArray); |
| 63 ASSERT(message->value.as_array.length == 4); | 67 ASSERT(message->value.as_array.length == 4); |
| 64 Dart_CObject* tag_message = message->value.as_array.values[0]; | 68 Dart_CObject* tag_message = message->value.as_array.values[0]; |
| 65 ASSERT(tag_message != NULL); | 69 ASSERT(tag_message != NULL); |
| 66 Dart_CObject* uri_message = message->value.as_array.values[1]; | 70 Dart_CObject* uri_message = message->value.as_array.values[1]; |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 ASSERT(results_ != NULL); | 188 ASSERT(results_ != NULL); |
| 185 } | 189 } |
| 186 ASSERT(results_ != NULL); | 190 ASSERT(results_ != NULL); |
| 187 ASSERT(results_length_ < results_capacity_); | 191 ASSERT(results_length_ < results_capacity_); |
| 188 results_[results_length_].Setup(message); | 192 results_[results_length_].Setup(message); |
| 189 results_length_++; | 193 results_length_++; |
| 190 ml.Notify(); | 194 ml.Notify(); |
| 191 } | 195 } |
| 192 | 196 |
| 193 | 197 |
| 194 void Loader::BlockUntilComplete() { | 198 void Loader::BlockUntilComplete(ProcessResult process_result) { |
| 195 MonitorLocker ml(monitor_); | 199 MonitorLocker ml(monitor_); |
| 196 | 200 |
| 197 while (true) { | 201 while (true) { |
| 198 // If |ProcessQueueLocked| returns false, we've hit an error and should | 202 // If |ProcessQueueLocked| returns false, we've hit an error and should |
| 199 // stop loading. | 203 // stop loading. |
| 200 if (!ProcessQueueLocked()) { | 204 if (!ProcessQueueLocked(process_result)) { |
| 201 break; | 205 break; |
| 202 } | 206 } |
| 203 | 207 |
| 204 // When |pending_operations_| hits 0, we are done loading. | 208 // When |pending_operations_| hits 0, we are done loading. |
| 205 if (pending_operations_ == 0) { | 209 if (pending_operations_ == 0) { |
| 206 break; | 210 break; |
| 207 } | 211 } |
| 208 | 212 |
| 209 // Wait to be notified about new I/O results. | 213 // Wait to be notified about new I/O results. |
| 210 ml.Wait(); | 214 ml.Wait(); |
| 211 } | 215 } |
| 212 } | 216 } |
| 213 | 217 |
| 214 | 218 |
| 215 static bool LibraryHandleError(Dart_Handle library, Dart_Handle error) { | 219 static bool LibraryHandleError(Dart_Handle library, Dart_Handle error) { |
| 216 if (!Dart_IsNull(library) && !Dart_IsError(library)) { | 220 if (!Dart_IsNull(library) && !Dart_IsError(library)) { |
| 217 ASSERT(Dart_IsLibrary(library)); | 221 ASSERT(Dart_IsLibrary(library)); |
| 218 Dart_Handle res = Dart_LibraryHandleError(library, error); | 222 Dart_Handle res = Dart_LibraryHandleError(library, error); |
| 219 if (Dart_IsNull(res)) { | 223 if (Dart_IsNull(res)) { |
| 220 // Error was handled by library. | 224 // Error was handled by library. |
| 221 return true; | 225 return true; |
| 222 } | 226 } |
| 223 } | 227 } |
| 224 return false; | 228 return false; |
| 225 } | 229 } |
| 226 | 230 |
| 227 | 231 |
| 228 bool Loader::ProcessResultLocked(Loader::IOResult* result) { | 232 bool Loader::ProcessResultLocked(Loader* loader, Loader::IOResult* result) { |
| 229 // We have to copy everything we care about out of |result| because after | 233 // We have to copy everything we care about out of |result| because after |
| 230 // dropping the lock below |result| may no longer valid. | 234 // dropping the lock below |result| may no longer valid. |
| 231 Dart_Handle uri = | 235 Dart_Handle uri = |
| 232 Dart_NewStringFromCString(reinterpret_cast<char*>(result->uri)); | 236 Dart_NewStringFromCString(reinterpret_cast<char*>(result->uri)); |
| 233 Dart_Handle library_uri = Dart_Null(); | 237 Dart_Handle library_uri = Dart_Null(); |
| 234 if (result->library_uri != NULL) { | 238 if (result->library_uri != NULL) { |
| 235 library_uri = | 239 library_uri = |
| 236 Dart_NewStringFromCString(reinterpret_cast<char*>(result->library_uri)); | 240 Dart_NewStringFromCString(reinterpret_cast<char*>(result->library_uri)); |
| 237 } | 241 } |
| 238 | 242 |
| 239 // A negative result tag indicates a loading error occurred in the service | 243 // A negative result tag indicates a loading error occurred in the service |
| 240 // isolate. The payload is a C string of the error message. | 244 // isolate. The payload is a C string of the error message. |
| 241 if (result->tag < 0) { | 245 if (result->tag < 0) { |
| 242 Dart_Handle library = Dart_LookupLibrary(uri); | 246 Dart_Handle library = Dart_LookupLibrary(uri); |
| 243 Dart_Handle error = Dart_NewStringFromUTF8(result->payload, | 247 Dart_Handle error = Dart_NewStringFromUTF8(result->payload, |
| 244 result->payload_length); | 248 result->payload_length); |
| 245 // If a library with the given uri exists, give it a chance to handle | 249 // If a library with the given uri exists, give it a chance to handle |
| 246 // the error. If the load requests stems from a deferred library load, | 250 // the error. If the load requests stems from a deferred library load, |
| 247 // an IO error is not fatal. | 251 // an IO error is not fatal. |
| 248 if (LibraryHandleError(library, error)) { | 252 if (LibraryHandleError(library, error)) { |
| 249 return true; | 253 return true; |
| 250 } | 254 } |
| 251 // Fall through | 255 // Fall through |
| 252 error_ = Dart_NewUnhandledExceptionError(error); | 256 loader->error_ = Dart_NewUnhandledExceptionError(error); |
| 253 return false; | 257 return false; |
| 254 } | 258 } |
| 255 | 259 |
| 256 | 260 |
| 257 // Check for payload and load accordingly. | 261 // Check for payload and load accordingly. |
| 258 bool is_snapshot = false; | 262 bool is_snapshot = false; |
| 259 const uint8_t* payload = result->payload; | 263 const uint8_t* payload = result->payload; |
| 260 intptr_t payload_length = result->payload_length; | 264 intptr_t payload_length = result->payload_length; |
| 261 payload = | 265 payload = |
| 262 DartUtils::SniffForMagicNumber(payload, | 266 DartUtils::SniffForMagicNumber(payload, |
| 263 &payload_length, | 267 &payload_length, |
| 264 &is_snapshot); | 268 &is_snapshot); |
| 265 Dart_Handle source = Dart_Null(); | 269 Dart_Handle source = Dart_Null(); |
| 266 if (!is_snapshot) { | 270 if (!is_snapshot) { |
| 267 source = Dart_NewStringFromUTF8(result->payload, | 271 source = Dart_NewStringFromUTF8(result->payload, |
| 268 result->payload_length); | 272 result->payload_length); |
| 269 if (Dart_IsError(source)) { | 273 if (Dart_IsError(source)) { |
| 270 error_ = DartUtils::NewError("%s is not a valid UTF-8 script", | 274 loader->error_ = DartUtils::NewError( |
| 271 reinterpret_cast<char*>(result->uri)); | 275 "%s is not a valid UTF-8 script", |
| 276 reinterpret_cast<char*>(result->uri)); |
| 272 return false; | 277 return false; |
| 273 } | 278 } |
| 274 } | 279 } |
| 275 intptr_t tag = result->tag; | 280 intptr_t tag = result->tag; |
| 276 | 281 |
| 277 // No touching. | 282 // No touching. |
| 278 result = NULL; | 283 result = NULL; |
| 279 | 284 |
| 280 // We must drop the lock here because the tag handler may be recursively | 285 // We must drop the lock here because the tag handler may be recursively |
| 281 // invoked and it will attempt to acquire the lock to queue more work. | 286 // invoked and it will attempt to acquire the lock to queue more work. |
| 282 monitor_->Exit(); | 287 loader->monitor_->Exit(); |
| 283 | 288 |
| 284 Dart_Handle dart_result = Dart_Null(); | 289 Dart_Handle dart_result = Dart_Null(); |
| 285 | 290 |
| 286 switch (tag) { | 291 switch (tag) { |
| 287 case Dart_kImportTag: | 292 case Dart_kImportTag: |
| 288 dart_result = Dart_LoadLibrary(uri, source, 0, 0); | 293 dart_result = Dart_LoadLibrary(uri, source, 0, 0); |
| 289 break; | 294 break; |
| 290 case Dart_kSourceTag: { | 295 case Dart_kSourceTag: { |
| 291 ASSERT(library_uri != Dart_Null()); | 296 ASSERT(library_uri != Dart_Null()); |
| 292 Dart_Handle library = Dart_LookupLibrary(library_uri); | 297 Dart_Handle library = Dart_LookupLibrary(library_uri); |
| 293 ASSERT(!Dart_IsError(library)); | 298 ASSERT(!Dart_IsError(library)); |
| 294 dart_result = Dart_LoadSource(library, uri, source, 0, 0); | 299 dart_result = Dart_LoadSource(library, uri, source, 0, 0); |
| 295 } | 300 } |
| 296 break; | 301 break; |
| 297 case Dart_kScriptTag: | 302 case Dart_kScriptTag: |
| 298 if (is_snapshot) { | 303 if (is_snapshot) { |
| 299 dart_result = Dart_LoadScriptFromSnapshot(payload, payload_length); | 304 dart_result = Dart_LoadScriptFromSnapshot(payload, payload_length); |
| 300 } else { | 305 } else { |
| 301 dart_result = Dart_LoadScript(uri, source, 0, 0); | 306 dart_result = Dart_LoadScript(uri, source, 0, 0); |
| 302 } | 307 } |
| 303 break; | 308 break; |
| 304 default: | 309 default: |
| 305 UNREACHABLE(); | 310 UNREACHABLE(); |
| 306 } | 311 } |
| 307 | 312 |
| 308 // Re-acquire the lock before exiting the function (it was held before entry), | 313 // Re-acquire the lock before exiting the function (it was held before entry), |
| 309 monitor_->Enter(); | 314 loader->monitor_->Enter(); |
| 310 if (Dart_IsError(dart_result)) { | 315 if (Dart_IsError(dart_result)) { |
| 311 // Remember the error if we encountered one. | 316 // Remember the error if we encountered one. |
| 312 error_ = dart_result; | 317 loader->error_ = dart_result; |
| 313 return false; | 318 return false; |
| 314 } | 319 } |
| 315 | 320 |
| 316 return true; | 321 return true; |
| 317 } | 322 } |
| 318 | 323 |
| 319 | 324 |
| 320 bool Loader::ProcessQueueLocked() { | 325 bool Loader::ProcessUrlLoadResultLocked(Loader* loader, |
| 326 Loader::IOResult* result) { |
| 327 // A negative result tag indicates a loading error occurred in the service |
| 328 // isolate. The payload is a C string of the error message. |
| 329 if (result->tag < 0) { |
| 330 Dart_Handle error = Dart_NewStringFromUTF8(result->payload, |
| 331 result->payload_length); |
| 332 loader->error_ = Dart_NewUnhandledExceptionError(error); |
| 333 return false; |
| 334 } |
| 335 loader->payload_length_ = result->payload_length; |
| 336 loader->payload_ = |
| 337 reinterpret_cast<uint8_t*>(::malloc(loader->payload_length_)); |
| 338 memmove(loader->payload_, result->payload, loader->payload_length_); |
| 339 return true; |
| 340 } |
| 341 |
| 342 |
| 343 bool Loader::ProcessQueueLocked(ProcessResult process_result) { |
| 321 bool hit_error = false; | 344 bool hit_error = false; |
| 322 for (intptr_t i = 0; i < results_length(); i++) { | 345 for (intptr_t i = 0; i < results_length(); i++) { |
| 323 if (!hit_error) { | 346 if (!hit_error) { |
| 324 hit_error = !ProcessResultLocked(&results_[i]); | 347 hit_error = !(*process_result)(this, &results_[i]); |
| 325 } | 348 } |
| 326 pending_operations_--; | 349 pending_operations_--; |
| 327 ASSERT(hit_error || (pending_operations_ >= 0)); | 350 ASSERT(hit_error || (pending_operations_ >= 0)); |
| 328 results_[i].Cleanup(); | 351 results_[i].Cleanup(); |
| 329 } | 352 } |
| 330 results_length_ = 0; | 353 results_length_ = 0; |
| 331 return !hit_error; | 354 return !hit_error; |
| 332 } | 355 } |
| 333 | 356 |
| 334 | 357 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 351 // Send the init message. | 374 // Send the init message. |
| 352 loader->Init(isolate_data->package_root, | 375 loader->Init(isolate_data->package_root, |
| 353 isolate_data->packages_file, | 376 isolate_data->packages_file, |
| 354 DartUtils::original_working_directory, | 377 DartUtils::original_working_directory, |
| 355 snapshot_uri); | 378 snapshot_uri); |
| 356 // Destroy the loader. The destructor does a bunch of leg work. | 379 // Destroy the loader. The destructor does a bunch of leg work. |
| 357 delete loader; | 380 delete loader; |
| 358 } | 381 } |
| 359 | 382 |
| 360 | 383 |
| 384 Dart_Handle Loader::LoadUrlContents(Dart_Handle url, |
| 385 uint8_t** payload, |
| 386 intptr_t* payload_length) { |
| 387 IsolateData* isolate_data = |
| 388 reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData()); |
| 389 ASSERT(isolate_data != NULL); |
| 390 ASSERT(!isolate_data->HasLoader()); |
| 391 Loader* loader = NULL; |
| 392 |
| 393 // Setup the loader. The constructor does a bunch of leg work. |
| 394 loader = new Loader(isolate_data); |
| 395 loader->Init(isolate_data->package_root, |
| 396 isolate_data->packages_file, |
| 397 DartUtils::original_working_directory, |
| 398 NULL); |
| 399 ASSERT(loader != NULL); |
| 400 ASSERT(isolate_data->HasLoader()); |
| 401 |
| 402 // Now send a load request to the service isolate. |
| 403 loader->SendRequest(Dart_kScriptTag, url, Dart_Null()); |
| 404 |
| 405 // Wait for a reply to the load request. |
| 406 loader->BlockUntilComplete(ProcessUrlLoadResultLocked); |
| 407 |
| 408 // Copy fields from the loader before deleting it. |
| 409 // The payload array itself which was malloced above is freed by |
| 410 // the caller of LoadUrlContents. |
| 411 Dart_Handle error = loader->error(); |
| 412 *payload = loader->payload_; |
| 413 *payload_length = loader->payload_length_; |
| 414 |
| 415 // Destroy the loader. The destructor does a bunch of leg work. |
| 416 delete loader; |
| 417 |
| 418 // An error occurred during loading. |
| 419 if (!Dart_IsNull(error)) { |
| 420 return error; |
| 421 } |
| 422 return Dart_Null(); |
| 423 } |
| 424 |
| 425 |
| 361 Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag, | 426 Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag, |
| 362 Dart_Handle library, | 427 Dart_Handle library, |
| 363 Dart_Handle url) { | 428 Dart_Handle url) { |
| 364 if (tag == Dart_kCanonicalizeUrl) { | 429 if (tag == Dart_kCanonicalizeUrl) { |
| 365 Dart_Handle library_url = Dart_LibraryUrl(library); | 430 Dart_Handle library_url = Dart_LibraryUrl(library); |
| 366 if (Dart_IsError(library_url)) { | 431 if (Dart_IsError(library_url)) { |
| 367 return library_url; | 432 return library_url; |
| 368 } | 433 } |
| 369 return Dart_DefaultCanonicalizeUrl(library_url, url); | 434 return Dart_DefaultCanonicalizeUrl(library_url, url); |
| 370 } | 435 } |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 ASSERT(isolate_data->HasLoader()); | 524 ASSERT(isolate_data->HasLoader()); |
| 460 | 525 |
| 461 loader->SendRequest(tag, | 526 loader->SendRequest(tag, |
| 462 url, | 527 url, |
| 463 (library != Dart_Null()) ? | 528 (library != Dart_Null()) ? |
| 464 Dart_LibraryUrl(library) : Dart_Null()); | 529 Dart_LibraryUrl(library) : Dart_Null()); |
| 465 | 530 |
| 466 if (blocking_call) { | 531 if (blocking_call) { |
| 467 // The outer invocation of the tag handler will block here until all nested | 532 // The outer invocation of the tag handler will block here until all nested |
| 468 // invocations complete. | 533 // invocations complete. |
| 469 loader->BlockUntilComplete(); | 534 loader->BlockUntilComplete(ProcessResultLocked); |
| 470 | 535 |
| 471 // Remember the error (if any). | 536 // Remember the error (if any). |
| 472 Dart_Handle error = loader->error(); | 537 Dart_Handle error = loader->error(); |
| 473 // Destroy the loader. The destructor does a bunch of leg work. | 538 // Destroy the loader. The destructor does a bunch of leg work. |
| 474 delete loader; | 539 delete loader; |
| 475 | 540 |
| 476 // An error occurred during loading. | 541 // An error occurred during loading. |
| 477 if (!Dart_IsNull(error)) { | 542 if (!Dart_IsNull(error)) { |
| 478 if (false && is_deferred_import) { | 543 if (false && is_deferred_import) { |
| 479 // This blocks handles transitive load errors caused by a deferred | 544 // This blocks handles transitive load errors caused by a deferred |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 625 MutexLocker ml(&loader_infos_lock_); | 690 MutexLocker ml(&loader_infos_lock_); |
| 626 Loader* loader = LoaderForLocked(dest_port_id); | 691 Loader* loader = LoaderForLocked(dest_port_id); |
| 627 if (loader == NULL) { | 692 if (loader == NULL) { |
| 628 return; | 693 return; |
| 629 } | 694 } |
| 630 loader->QueueMessage(message); | 695 loader->QueueMessage(message); |
| 631 } | 696 } |
| 632 | 697 |
| 633 } // namespace bin | 698 } // namespace bin |
| 634 } // namespace dart | 699 } // namespace dart |
| OLD | NEW |