21
21
#include " vm/message_handler.h"
22
22
#include " vm/message_snapshot.h"
23
23
#include " vm/object.h"
24
+ #include " vm/object_graph_copy.h"
24
25
#include " vm/object_store.h"
25
26
#include " vm/port.h"
26
27
#include " vm/resolver.h"
@@ -319,6 +320,7 @@ class IsolateSpawnState {
319
320
Dart_Port origin_id,
320
321
const char * script_url,
321
322
const Function& func,
323
+ PersistentHandle* closure_tuple_handle,
322
324
SerializedObjectBuffer* message_buffer,
323
325
const char * package_config,
324
326
bool paused,
@@ -353,10 +355,16 @@ class IsolateSpawnState {
353
355
const char * class_name () const { return class_name_; }
354
356
const char * function_name () const { return function_name_; }
355
357
const char * debug_name () const { return debug_name_; }
356
- bool is_spawn_uri () const { return library_url_ == nullptr ; }
358
+ bool is_spawn_uri () const {
359
+ return library_url_ == nullptr && // No top-level entrypoint.
360
+ closure_tuple_handle_ == nullptr ; // No closure entrypoint.
361
+ }
357
362
bool paused () const { return paused_; }
358
363
bool errors_are_fatal () const { return errors_are_fatal_; }
359
364
Dart_IsolateFlags* isolate_flags () { return &isolate_flags_; }
365
+ PersistentHandle* closure_tuple_handle () const {
366
+ return closure_tuple_handle_;
367
+ }
360
368
361
369
ObjectPtr ResolveFunction ();
362
370
ObjectPtr BuildArgs (Thread* thread);
@@ -376,6 +384,7 @@ class IsolateSpawnState {
376
384
const char * class_name_ = nullptr ;
377
385
const char * function_name_ = nullptr ;
378
386
const char * debug_name_;
387
+ PersistentHandle* closure_tuple_handle_ = nullptr ;
379
388
IsolateGroup* isolate_group_;
380
389
std::unique_ptr<Message> serialized_args_;
381
390
std::unique_ptr<Message> serialized_message_;
@@ -396,6 +405,7 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port,
396
405
Dart_Port origin_id,
397
406
const char * script_url,
398
407
const Function& func,
408
+ PersistentHandle* closure_tuple_handle,
399
409
SerializedObjectBuffer* message_buffer,
400
410
const char * package_config,
401
411
bool paused,
@@ -411,25 +421,34 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port,
411
421
script_url_ (script_url),
412
422
package_config_ (package_config),
413
423
debug_name_ (debug_name),
424
+ closure_tuple_handle_ (closure_tuple_handle),
414
425
isolate_group_ (isolate_group),
415
426
serialized_args_ (nullptr ),
416
427
serialized_message_ (message_buffer->StealMessage ()),
417
428
paused_ (paused),
418
429
errors_are_fatal_ (errors_are_fatal) {
430
+ // Either we have a top-level function or we have a closure.
431
+ ASSERT ((closure_tuple_handle_ != nullptr ) == func.IsNull ());
432
+
419
433
auto thread = Thread::Current ();
420
434
auto isolate = thread->isolate ();
421
- auto zone = thread->zone ();
422
- const auto & cls = Class::Handle (zone, func.Owner ());
423
- const auto & lib = Library::Handle (zone, cls.library ());
424
- const auto & lib_url = String::Handle (zone, lib.url ());
425
- library_url_ = NewConstChar (lib_url.ToCString ());
426
-
427
- String& func_name = String::Handle (zone);
428
- func_name = func.name ();
429
- function_name_ = NewConstChar (String::ScrubName (func_name));
430
- if (!cls.IsTopLevel ()) {
431
- const auto & class_name = String::Handle (zone, cls.Name ());
432
- class_name_ = NewConstChar (class_name.ToCString ());
435
+
436
+ if (!func.IsNull ()) {
437
+ auto zone = thread->zone ();
438
+ const auto & cls = Class::Handle (zone, func.Owner ());
439
+ const auto & lib = Library::Handle (zone, cls.library ());
440
+ const auto & lib_url = String::Handle (zone, lib.url ());
441
+ library_url_ = NewConstChar (lib_url.ToCString ());
442
+
443
+ String& func_name = String::Handle (zone);
444
+ func_name = func.name ();
445
+ function_name_ = NewConstChar (String::ScrubName (func_name));
446
+ if (!cls.IsTopLevel ()) {
447
+ const auto & class_name = String::Handle (zone, cls.Name ());
448
+ class_name_ = NewConstChar (class_name.ToCString ());
449
+ }
450
+ } else {
451
+ ASSERT (closure_tuple_handle != nullptr );
433
452
}
434
453
435
454
// Inherit flags from spawning isolate.
@@ -446,14 +465,14 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port,
446
465
Dart_Port on_exit_port,
447
466
Dart_Port on_error_port,
448
467
const char * debug_name,
449
- IsolateGroup* group )
468
+ IsolateGroup* isolate_group )
450
469
: parent_port_ (parent_port),
451
470
on_exit_port_ (on_exit_port),
452
471
on_error_port_ (on_error_port),
453
472
script_url_ (script_url),
454
473
package_config_ (package_config),
455
474
debug_name_ (debug_name),
456
- isolate_group_ (group ),
475
+ isolate_group_ (isolate_group ),
457
476
serialized_args_ (args_buffer->StealMessage ()),
458
477
serialized_message_ (message_buffer->StealMessage ()),
459
478
isolate_flags_ (),
@@ -734,20 +753,32 @@ class SpawnIsolateTask : public ThreadPool::Task {
734
753
bool EnqueueEntrypointInvocationAndNotifySpawner (Thread* thread) {
735
754
auto isolate = thread->isolate ();
736
755
auto zone = thread->zone ();
756
+ const bool is_spawn_uri = state_->is_spawn_uri ();
737
757
738
758
// Step 1) Resolve the entrypoint function.
739
- auto & result = Object::Handle (zone, state_->ResolveFunction ());
740
- const bool is_spawn_uri = state_->is_spawn_uri ();
741
- if (result.IsError ()) {
742
- ASSERT (is_spawn_uri);
743
- ReportError (" Failed to resolve entrypoint function." );
744
- return false ;
759
+ auto & entrypoint_closure = Closure::Handle (zone);
760
+ if (state_->closure_tuple_handle () != nullptr ) {
761
+ const auto & result = Object::Handle (
762
+ zone,
763
+ ReadObjectGraphCopyMessage (thread, state_->closure_tuple_handle ()));
764
+ if (result.IsError ()) {
765
+ ReportError (
766
+ " Failed to deserialize the passed entrypoint to the new isolate." );
767
+ return false ;
768
+ }
769
+ entrypoint_closure = Closure::RawCast (result.ptr ());
770
+ } else {
771
+ const auto & result = Object::Handle (zone, state_->ResolveFunction ());
772
+ if (result.IsError ()) {
773
+ ASSERT (is_spawn_uri);
774
+ ReportError (" Failed to resolve entrypoint function." );
775
+ return false ;
776
+ }
777
+ ASSERT (result.IsFunction ());
778
+ auto & func = Function::Handle (zone, Function::Cast (result).ptr ());
779
+ func = func.ImplicitClosureFunction ();
780
+ entrypoint_closure = func.ImplicitStaticClosure ();
745
781
}
746
- ASSERT (result.IsFunction ());
747
- auto & func = Function::Handle (zone, Function::Cast (result).ptr ());
748
- func = func.ImplicitClosureFunction ();
749
- const auto & entrypoint_closure =
750
- Object::Handle (zone, func.ImplicitStaticClosure ());
751
782
752
783
// Step 2) Enqueue delayed invocation of entrypoint callback.
753
784
const auto & args_obj = Object::Handle (zone, state_->BuildArgs (thread));
@@ -776,7 +807,8 @@ class SpawnIsolateTask : public ThreadPool::Task {
776
807
const auto & entry_point =
777
808
Function::Handle (zone, lib.LookupLocalFunction (entry_name));
778
809
ASSERT (entry_point.IsFunction () && !entry_point.IsNull ());
779
- result = DartEntry::InvokeFunction (entry_point, args);
810
+ const auto & result =
811
+ Object::Handle (zone, DartEntry::InvokeFunction (entry_point, args));
780
812
if (result.IsError ()) {
781
813
ReportError (" Failed to enqueue delayed entrypoint invocation." );
782
814
return false ;
@@ -858,10 +890,23 @@ static const char* String2UTF8(const String& str) {
858
890
return result;
859
891
}
860
892
893
+ static FunctionPtr GetTopLevelFunction (Zone* zone, const Instance& closure) {
894
+ if (closure.IsClosure ()) {
895
+ auto & func = Function::Handle (zone);
896
+ func = Closure::Cast (closure).function ();
897
+ if (func.IsImplicitClosureFunction () && func.is_static ()) {
898
+ ASSERT (Closure::Cast (closure).context () == Context::null ());
899
+ // Get the parent function so that we get the right function name.
900
+ return func.parent_function ();
901
+ }
902
+ }
903
+ return Function::null ();
904
+ }
905
+
861
906
DEFINE_NATIVE_ENTRY (Isolate_spawnFunction, 0 , 10 ) {
862
907
GET_NON_NULL_NATIVE_ARGUMENT (SendPort, port, arguments->NativeArgAt (0 ));
863
908
GET_NON_NULL_NATIVE_ARGUMENT (String, script_uri, arguments->NativeArgAt (1 ));
864
- GET_NON_NULL_NATIVE_ARGUMENT (Instance , closure, arguments->NativeArgAt (2 ));
909
+ GET_NON_NULL_NATIVE_ARGUMENT (Closure , closure, arguments->NativeArgAt (2 ));
865
910
GET_NON_NULL_NATIVE_ARGUMENT (Instance, message, arguments->NativeArgAt (3 ));
866
911
GET_NON_NULL_NATIVE_ARGUMENT (Bool, paused, arguments->NativeArgAt (4 ));
867
912
GET_NATIVE_ARGUMENT (Bool, fatalErrors, arguments->NativeArgAt (5 ));
@@ -870,51 +915,62 @@ DEFINE_NATIVE_ENTRY(Isolate_spawnFunction, 0, 10) {
870
915
GET_NATIVE_ARGUMENT (String, packageConfig, arguments->NativeArgAt (8 ));
871
916
GET_NATIVE_ARGUMENT (String, debugName, arguments->NativeArgAt (9 ));
872
917
873
- if (closure.IsClosure ()) {
874
- Function& func = Function::Handle ();
875
- func = Closure::Cast (closure).function ();
876
- if (func.IsImplicitClosureFunction () && func.is_static ()) {
877
- #if defined(DEBUG)
878
- Context& ctx = Context::Handle ();
879
- ctx = Closure::Cast (closure).context ();
880
- ASSERT (ctx.IsNull ());
881
- #endif
882
- // Get the parent function so that we get the right function name.
883
- func = func.parent_function ();
884
-
885
- bool fatal_errors = fatalErrors.IsNull () ? true : fatalErrors.value ();
886
- Dart_Port on_exit_port = onExit.IsNull () ? ILLEGAL_PORT : onExit.Id ();
887
- Dart_Port on_error_port = onError.IsNull () ? ILLEGAL_PORT : onError.Id ();
888
-
889
- // We first try to serialize the message. In case the message is not
890
- // serializable this will throw an exception.
891
- SerializedObjectBuffer message_buffer;
892
- message_buffer.set_message (WriteMessage (
893
- /* can_send_any_object */ true ,
894
- /* same_group */ FLAG_enable_isolate_groups, message, ILLEGAL_PORT,
895
- Message::kNormalPriority ));
896
-
897
- const char * utf8_package_config =
898
- packageConfig.IsNull () ? NULL : String2UTF8 (packageConfig);
899
- const char * utf8_debug_name =
900
- debugName.IsNull () ? NULL : String2UTF8 (debugName);
901
-
902
- std::unique_ptr<IsolateSpawnState> state (new IsolateSpawnState (
903
- port.Id (), isolate->origin_id (), String2UTF8 (script_uri), func,
904
- &message_buffer, utf8_package_config, paused.value (), fatal_errors,
905
- on_exit_port, on_error_port, utf8_debug_name, isolate->group ()));
906
-
907
- // Since this is a call to Isolate.spawn, copy the parent isolate's code.
908
- state->isolate_flags ()->copy_parent_code = true ;
909
-
910
- isolate->group ()->thread_pool ()->Run <SpawnIsolateTask>(isolate,
911
- std::move (state));
912
- return Object::null ();
918
+ const auto & func = Function::Handle (zone, GetTopLevelFunction (zone, closure));
919
+ PersistentHandle* closure_tuple_handle = nullptr ;
920
+ if (func.IsNull ()) {
921
+ if (!FLAG_enable_isolate_groups) {
922
+ const String& msg = String::Handle (String::New (
923
+ " Isolate.spawn expects to be passed a static or top-level function" ));
924
+ Exceptions::ThrowArgumentError (msg);
925
+ } else {
926
+ // We have a non-toplevel closure that we might need to copy.
927
+ // Result will be [<closure-copy>, <objects-in-msg-to-rehash>]
928
+ const auto & closure_copy_tuple = Object::Handle (
929
+ zone, CopyMutableObjectGraph (closure)); // Throws if it fails.
930
+ ASSERT (closure_copy_tuple.IsArray ());
931
+ ASSERT (Object::Handle (zone, Array::Cast (closure_copy_tuple).At (0 ))
932
+ .IsClosure ());
933
+ closure_tuple_handle =
934
+ isolate->group ()->api_state ()->AllocatePersistentHandle ();
935
+ closure_tuple_handle->set_ptr (closure_copy_tuple.ptr ());
913
936
}
914
937
}
915
- const String& msg = String::Handle (String::New (
916
- " Isolate.spawn expects to be passed a static or top-level function" ));
917
- Exceptions::ThrowArgumentError (msg);
938
+
939
+ bool fatal_errors = fatalErrors.IsNull () ? true : fatalErrors.value ();
940
+ Dart_Port on_exit_port = onExit.IsNull () ? ILLEGAL_PORT : onExit.Id ();
941
+ Dart_Port on_error_port = onError.IsNull () ? ILLEGAL_PORT : onError.Id ();
942
+
943
+ // We first try to serialize the message. In case the message is not
944
+ // serializable this will throw an exception.
945
+ SerializedObjectBuffer message_buffer;
946
+ message_buffer.set_message (WriteMessage (
947
+ /* can_send_any_object */ true ,
948
+ /* same_group */ FLAG_enable_isolate_groups, message, ILLEGAL_PORT,
949
+ Message::kNormalPriority ));
950
+
951
+ const char * utf8_package_config =
952
+ packageConfig.IsNull () ? NULL : String2UTF8 (packageConfig);
953
+ const char * utf8_debug_name =
954
+ debugName.IsNull () ? NULL : String2UTF8 (debugName);
955
+ if (closure_tuple_handle != nullptr && utf8_debug_name == nullptr ) {
956
+ ASSERT (func.IsNull ());
957
+
958
+ const auto & closure_function = Function::Handle (zone, closure.function ());
959
+ utf8_debug_name =
960
+ NewConstChar (closure_function.QualifiedUserVisibleNameCString ());
961
+ }
962
+
963
+ std::unique_ptr<IsolateSpawnState> state (new IsolateSpawnState (
964
+ port.Id (), isolate->origin_id (), String2UTF8 (script_uri), func,
965
+ closure_tuple_handle, &message_buffer, utf8_package_config,
966
+ paused.value (), fatal_errors, on_exit_port, on_error_port,
967
+ utf8_debug_name, isolate->group ()));
968
+
969
+ // Since this is a call to Isolate.spawn, copy the parent isolate's code.
970
+ state->isolate_flags ()->copy_parent_code = true ;
971
+
972
+ isolate->group ()->thread_pool ()->Run <SpawnIsolateTask>(isolate,
973
+ std::move (state));
918
974
return Object::null ();
919
975
}
920
976
0 commit comments