OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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 #include "platform/assert.h" | 5 #include "platform/assert.h" |
6 #include "vm/bootstrap_natives.h" | 6 #include "vm/bootstrap_natives.h" |
7 #include "vm/class_finalizer.h" | 7 #include "vm/class_finalizer.h" |
8 #include "vm/dart.h" | 8 #include "vm/dart.h" |
9 #include "vm/dart_api_impl.h" | 9 #include "vm/dart_api_impl.h" |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 | 46 |
47 static uint8_t* SerializeObject(const Instance& obj) { | 47 static uint8_t* SerializeObject(const Instance& obj) { |
48 uint8_t* result = NULL; | 48 uint8_t* result = NULL; |
49 SnapshotWriter writer(Snapshot::kMessage, &result, &allocator); | 49 SnapshotWriter writer(Snapshot::kMessage, &result, &allocator); |
50 writer.WriteObject(obj.raw()); | 50 writer.WriteObject(obj.raw()); |
51 writer.FinalizeBuffer(); | 51 writer.FinalizeBuffer(); |
52 return result; | 52 return result; |
53 } | 53 } |
54 | 54 |
55 | 55 |
| 56 // TODO(turnidge): Taking down the whole vm when an isolate fails is |
| 57 // bad. Change this. |
56 static void ProcessError(const Object& obj) { | 58 static void ProcessError(const Object& obj) { |
57 ASSERT(obj.IsError()); | 59 ASSERT(obj.IsError()); |
58 Error& error = Error::Handle(); | 60 Error& error = Error::Handle(); |
59 error ^= obj.raw(); | 61 error ^= obj.raw(); |
60 OS::PrintErr("%s\n", error.ToErrorCString()); | 62 OS::PrintErr("%s\n", error.ToErrorCString()); |
61 exit(255); | 63 exit(255); |
62 } | 64 } |
63 | 65 |
64 | 66 |
65 static void ThrowErrorException(Exceptions::ExceptionType type, | 67 static void ThrowErrorException(Exceptions::ExceptionType type, |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 | 266 |
265 static char* BuildIsolateName(const char* script_name, | 267 static char* BuildIsolateName(const char* script_name, |
266 const char* class_name, | 268 const char* class_name, |
267 const char* func_name) { | 269 const char* func_name) { |
268 // Skip past any slashes in the script name. | 270 // Skip past any slashes in the script name. |
269 const char* last_slash = strrchr(script_name, '/'); | 271 const char* last_slash = strrchr(script_name, '/'); |
270 if (last_slash != NULL) { | 272 if (last_slash != NULL) { |
271 script_name = last_slash + 1; | 273 script_name = last_slash + 1; |
272 } | 274 } |
273 | 275 |
274 const char* kFormat = "%s/%s.%s"; | 276 char* chars = NULL; |
275 intptr_t len = OS::SNPrint(NULL, 0, kFormat, script_name, class_name, | 277 if (class_name && class_name[0] != '\0') { |
276 func_name) + 1; | 278 const char* kFormat = "%s/%s.%s"; |
277 char* chars = reinterpret_cast<char*>( | 279 intptr_t len = OS::SNPrint(NULL, 0, kFormat, script_name, class_name, |
278 Isolate::Current()->current_zone()->Allocate(len)); | 280 func_name) + 1; |
279 OS::SNPrint(chars, len, kFormat, script_name, class_name, func_name); | 281 chars = reinterpret_cast<char*>( |
| 282 Isolate::Current()->current_zone()->Allocate(len)); |
| 283 OS::SNPrint(chars, len, kFormat, script_name, class_name, func_name); |
| 284 } else { |
| 285 const char* kFormat = "%s/%s"; |
| 286 intptr_t len = OS::SNPrint(NULL, 0, kFormat, script_name, func_name) + 1; |
| 287 chars = reinterpret_cast<char*>( |
| 288 Isolate::Current()->current_zone()->Allocate(len)); |
| 289 OS::SNPrint(chars, len, kFormat, script_name, func_name); |
| 290 } |
280 return chars; | 291 return chars; |
281 } | 292 } |
282 | 293 |
283 | 294 |
284 DEFINE_NATIVE_ENTRY(IsolateNatives_start, 2) { | 295 DEFINE_NATIVE_ENTRY(IsolateNatives_start, 2) { |
285 Isolate* preserved_isolate = Isolate::Current(); | 296 Isolate* preserved_isolate = Isolate::Current(); |
286 const Instance& runnable = Instance::CheckedHandle(arguments->At(0)); | 297 const Instance& runnable = Instance::CheckedHandle(arguments->At(0)); |
287 const Class& runnable_class = Class::Handle(runnable.clazz()); | 298 const Class& runnable_class = Class::Handle(runnable.clazz()); |
288 const char* class_name = String::Handle(runnable_class.Name()).ToCString(); | 299 const char* class_name = String::Handle(runnable_class.Name()).ToCString(); |
289 const Library& library = Library::Handle(runnable_class.library()); | 300 const Library& library = Library::Handle(runnable_class.library()); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 intptr_t send_id = Smi::CheckedHandle(arguments->At(0)).Value(); | 387 intptr_t send_id = Smi::CheckedHandle(arguments->At(0)).Value(); |
377 intptr_t reply_id = Smi::CheckedHandle(arguments->At(1)).Value(); | 388 intptr_t reply_id = Smi::CheckedHandle(arguments->At(1)).Value(); |
378 // TODO(iposva): Allow for arbitrary messages to be sent. | 389 // TODO(iposva): Allow for arbitrary messages to be sent. |
379 uint8_t* data = SerializeObject(Instance::CheckedHandle(arguments->At(2))); | 390 uint8_t* data = SerializeObject(Instance::CheckedHandle(arguments->At(2))); |
380 | 391 |
381 // TODO(turnidge): Throw an exception when the return value is false? | 392 // TODO(turnidge): Throw an exception when the return value is false? |
382 PortMap::PostMessage(new Message( | 393 PortMap::PostMessage(new Message( |
383 send_id, reply_id, data, Message::kNormalPriority)); | 394 send_id, reply_id, data, Message::kNormalPriority)); |
384 } | 395 } |
385 | 396 |
| 397 |
| 398 static void ThrowIllegalArgException(const String& message) { |
| 399 GrowableArray<const Object*> args(1); |
| 400 args.Add(&message); |
| 401 Exceptions::ThrowByType(Exceptions::kIllegalArgument, args); |
| 402 } |
| 403 |
| 404 |
| 405 static void ThrowIsolateSpawnException(const String& message) { |
| 406 GrowableArray<const Object*> args(1); |
| 407 args.Add(&message); |
| 408 Exceptions::ThrowByType(Exceptions::kIsolateSpawn, args); |
| 409 } |
| 410 |
| 411 |
| 412 class SpawnState { |
| 413 public: |
| 414 explicit SpawnState(const Function& func) |
| 415 : isolate_(NULL), |
| 416 library_url_(NULL), |
| 417 function_name_(NULL) { |
| 418 const Class& cls = Class::Handle(func.owner()); |
| 419 ASSERT(cls.IsTopLevel()); |
| 420 const Library& lib = Library::Handle(cls.library()); |
| 421 const String& lib_url = String::Handle(lib.url()); |
| 422 library_url_ = strdup(lib_url.ToCString()); |
| 423 |
| 424 const String& func_name = String::Handle(func.name()); |
| 425 function_name_ = strdup(func_name.ToCString()); |
| 426 } |
| 427 |
| 428 ~SpawnState() { |
| 429 free(library_url_); |
| 430 free(function_name_); |
| 431 } |
| 432 |
| 433 Isolate* isolate() const { return isolate_; } |
| 434 void set_isolate(Isolate* value) { isolate_ = value; } |
| 435 char* library_url() const { return library_url_; } |
| 436 char* function_name() const { return function_name_; } |
| 437 |
| 438 RawFunction* ResolveFunction() { |
| 439 const String& lib_url = |
| 440 String::Handle(String::NewSymbol(library_url())); |
| 441 const String& func_name = |
| 442 String::Handle(String::NewSymbol(function_name())); |
| 443 |
| 444 const Library& lib = Library::Handle(Library::LookupLibrary(lib_url)); |
| 445 if (lib.IsNull() || lib.IsError()) { |
| 446 return Function::null(); |
| 447 } |
| 448 return lib.LookupLocalFunction(func_name); |
| 449 } |
| 450 |
| 451 void Cleanup() { |
| 452 Isolate* saved = Isolate::Current(); |
| 453 Isolate::SetCurrent(isolate()); |
| 454 Dart::ShutdownIsolate(); |
| 455 Isolate::SetCurrent(saved); |
| 456 } |
| 457 |
| 458 private: |
| 459 Isolate* isolate_; |
| 460 char* library_url_; |
| 461 char* function_name_; |
| 462 }; |
| 463 |
| 464 |
| 465 static bool CreateIsolate(SpawnState* state, char** error) { |
| 466 Isolate* parent_isolate = Isolate::Current(); |
| 467 |
| 468 Dart_IsolateCreateCallback callback = Isolate::CreateCallback(); |
| 469 ASSERT(callback); |
| 470 const char* isolate_name = BuildIsolateName(state->library_url(), |
| 471 "", |
| 472 state->function_name()); |
| 473 void* init_data = parent_isolate->init_callback_data(); |
| 474 bool retval = (callback)(isolate_name, init_data, error); |
| 475 if (retval) { |
| 476 Isolate* child_isolate = Isolate::Current(); |
| 477 ASSERT(child_isolate); |
| 478 state->set_isolate(child_isolate); |
| 479 |
| 480 // Attempt to resolve the entry function now, so that we fail fast |
| 481 // in the case that the embedder's isolate create callback is |
| 482 // violating its contract. |
| 483 { |
| 484 Zone zone(child_isolate); |
| 485 HandleScope handle_scope(child_isolate); |
| 486 const Function& func = Function::Handle(state->ResolveFunction()); |
| 487 if (func.IsNull()) { |
| 488 *error = strdup(zone.PrintToString( |
| 489 "Internal error while starting isolate '%s': " |
| 490 "unable to resolve entry function '%s'.", |
| 491 child_isolate->name(), state->function_name())); |
| 492 retval = false; |
| 493 } |
| 494 } |
| 495 } |
| 496 if (!retval) { |
| 497 Dart::ShutdownIsolate(); |
| 498 } |
| 499 Isolate::SetCurrent(parent_isolate); |
| 500 return retval; |
| 501 } |
| 502 |
| 503 |
| 504 static void RunIsolate2(uword parameter) { |
| 505 SpawnState* state = reinterpret_cast<SpawnState*>(parameter); |
| 506 Isolate* isolate = state->isolate(); |
| 507 |
| 508 Isolate::SetCurrent(isolate); |
| 509 // Intialize stack limit in case we are running isolate in a |
| 510 // different thread than in which it was initialized. |
| 511 isolate->SetStackLimitFromCurrentTOS(reinterpret_cast<uword>(&isolate)); |
| 512 |
| 513 { |
| 514 Zone zone(isolate); |
| 515 HandleScope handle_scope(isolate); |
| 516 ASSERT(ClassFinalizer::FinalizePendingClasses()); |
| 517 Object& result = Object::Handle(); |
| 518 |
| 519 const Function& func = Function::Handle(state->ResolveFunction()); |
| 520 delete state; |
| 521 state = NULL; |
| 522 ASSERT(!func.IsNull()); |
| 523 |
| 524 GrowableArray<const Object*> args(0); |
| 525 const Array& kNoArgNames = Array::Handle(); |
| 526 result = DartEntry::InvokeStatic(func, args, kNoArgNames); |
| 527 if (result.IsError()) { |
| 528 ProcessError(result); |
| 529 } |
| 530 |
| 531 result = isolate->StandardRunLoop(); |
| 532 if (result.IsError()) { |
| 533 ProcessError(result); |
| 534 } |
| 535 ASSERT(result.IsNull()); |
| 536 } |
| 537 Dart::ShutdownIsolate(); |
| 538 } |
| 539 |
| 540 |
| 541 DEFINE_NATIVE_ENTRY(isolate_spawnFunction, 1) { |
| 542 GET_NATIVE_ARGUMENT(Closure, closure, arguments->At(0)); |
| 543 const Function& func = Function::Handle(closure.function()); |
| 544 const Class& cls = Class::Handle(func.owner()); |
| 545 if (!func.IsClosureFunction() || !func.is_static() || !cls.IsTopLevel()) { |
| 546 const String& msg = String::Handle(String::New( |
| 547 "spawnFunction expects to be passed a closure to a top-level static " |
| 548 "function")); |
| 549 ThrowIllegalArgException(msg); |
| 550 } |
| 551 |
| 552 #if defined(DEBUG) |
| 553 const Context& ctx = Context::Handle(closure.context()); |
| 554 ASSERT(ctx.num_variables() == 0); |
| 555 #endif |
| 556 |
| 557 // Create a new isolate. |
| 558 char* error = NULL; |
| 559 SpawnState* state = new SpawnState(func); |
| 560 if (!CreateIsolate(state, &error)) { |
| 561 delete state; |
| 562 const String& msg = String::Handle(String::New(error)); |
| 563 ThrowIsolateSpawnException(msg); |
| 564 } |
| 565 |
| 566 // Try to create a SendPort for the new isolate. |
| 567 const Object& port = |
| 568 Object::Handle(SendPortCreate(state->isolate()->main_port())); |
| 569 if (port.IsError()) { |
| 570 state->Cleanup(); |
| 571 delete state; |
| 572 Exceptions::PropagateError(port); |
| 573 } |
| 574 |
| 575 // Start the new isolate. |
| 576 int result = Thread::Start(RunIsolate2, reinterpret_cast<uword>(state)); |
| 577 if (result != 0) { |
| 578 const String& msg = String::Handle(String::NewFormatted( |
| 579 "Failed to start thread for isolate '%s'. Error code '%d'.", |
| 580 state->isolate()->name(), result)); |
| 581 state->Cleanup(); |
| 582 delete state; |
| 583 ThrowIsolateSpawnException(msg); |
| 584 } |
| 585 |
| 586 arguments->SetReturn(port); |
| 587 } |
| 588 |
| 589 |
| 590 DEFINE_NATIVE_ENTRY(isolate_getPortInternal, 0) { |
| 591 const Object& port = Object::Handle(ReceivePortCreate(isolate->main_port())); |
| 592 if (port.IsError()) { |
| 593 Exceptions::PropagateError(port); |
| 594 } |
| 595 arguments->SetReturn(port); |
| 596 } |
| 597 |
386 } // namespace dart | 598 } // namespace dart |
OLD | NEW |