diff --git a/DartTest2/.dart_tool/pub/bin/sdk-version b/DartTest2/.dart_tool/pub/bin/sdk-version new file mode 100644 index 0000000..7ec1d6d --- /dev/null +++ b/DartTest2/.dart_tool/pub/bin/sdk-version @@ -0,0 +1 @@ +2.1.0 diff --git a/DartTest2/.dart_tool/pub/bin/vector_math/mesh_generator.dart.snapshot.dart2 b/DartTest2/.dart_tool/pub/bin/vector_math/mesh_generator.dart.snapshot.dart2 new file mode 100644 index 0000000..c925a3f Binary files /dev/null and b/DartTest2/.dart_tool/pub/bin/vector_math/mesh_generator.dart.snapshot.dart2 differ diff --git a/DartTest2/.packages b/DartTest2/.packages new file mode 100644 index 0000000..4cd224a --- /dev/null +++ b/DartTest2/.packages @@ -0,0 +1,3 @@ +# Generated by pub on 2019-01-04 21:26:46.715864. +vector_math:file:///C:/Users/jeff/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/vector_math-2.0.8/lib/ +dart_test:lib/ diff --git a/DartTest2/DartHelpers.cpp b/DartTest2/DartHelpers.cpp new file mode 100644 index 0000000..a0869a2 --- /dev/null +++ b/DartTest2/DartHelpers.cpp @@ -0,0 +1,35 @@ +#include "DartHelpers.h" + +#include + +namespace dh +{ + std::string StdStringFromDart(Dart_Handle dartString) + { + uint8_t* data = nullptr; + intptr_t length = 0; + if (Dart_IsError(Dart_StringToUTF8(dartString, &data, &length))) + return std::string(); + return std::string(reinterpret_cast(data), length); + } + + bool LogIfError(Dart_Handle handle) + { + if (Dart_IsUnhandledExceptionError(handle)) + { + Dart_Handle stackTrace = Dart_ErrorGetStackTrace(handle); + const std::string traceString = StdStringFromDart(Dart_ToString(stackTrace)); + std::cout << "Dart Unhandled Exception: " << traceString; + return true; + } + else if (Dart_IsError(handle)) + { + std::cout << "Dart Error: " << Dart_GetError(handle); + return true; + } + else + { + return false; + } + } +} \ No newline at end of file diff --git a/DartTest2/DartHelpers.h b/DartTest2/DartHelpers.h new file mode 100644 index 0000000..f3df78f --- /dev/null +++ b/DartTest2/DartHelpers.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include "include/dart_api.h" + +// A lot of this duplicates what's in FML or Tonic, but since those +// are part of the Flutter repository I've duplicated them here +namespace dh +{ + std::string StdStringFromDart(Dart_Handle dartString); + bool LogIfError(Dart_Handle handle); + + class DartIsolateScope + { + public: + DartIsolateScope(Dart_Isolate isolate) + : _isolate(isolate) + { + _previous = Dart_CurrentIsolate(); + if (_previous == _isolate) + return; + if (_previous) + Dart_ExitIsolate(); + Dart_EnterIsolate(_isolate); + } + + ~DartIsolateScope() + { + Dart_Isolate current = Dart_CurrentIsolate(); + if (_previous == _isolate) + return; + if (current) + Dart_ExitScope(); + if (_previous) + Dart_EnterIsolate(_previous); + } + + private: + Dart_Isolate _isolate; + Dart_Isolate _previous; + }; +} \ No newline at end of file diff --git a/DartTest2/DartIsolate.cpp b/DartTest2/DartIsolate.cpp new file mode 100644 index 0000000..5223ed2 --- /dev/null +++ b/DartTest2/DartIsolate.cpp @@ -0,0 +1,244 @@ +#include "DartIsolate.h" + +#include + +#include "DartHelpers.h" +#include "DartIsolateGroupData.h" + + +DartIsolate::DartIsolate() +{ + _phase = Phase::Uninitialized; +} + +bool DartIsolate::Initialize(Dart_Isolate dartIsolate) +{ + if (_phase != Phase::Uninitialized) + return false; + + if (dartIsolate == nullptr) + return false; + + if (Dart_CurrentIsolate() != dartIsolate) + return false; + + _isolate = dartIsolate; + + /// TODO: Check if this exit isolate is correct - comment from flutter: + // We are entering a new scope (for the first time since initialization) and + // we want to restore the current scope to null when we exit out of this + // method. This balances the implicit Dart_EnterIsolate call made by + // Dart_CreateIsolateGroup (which calls the Initialize). + Dart_ExitIsolate(); + + dh::DartIsolateScope scope(_isolate); + + if (LogIfError(Dart_SetLibraryTagHandler(HandleLibraryTag)) + { + return false; + } + +} + +Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate( + const char* packageRoot, + const char* packageConfig, + Dart_IsolateFlags* flags, + char** error) +{ + + flags->load_vmservice_library = true; + DartIsolate::CreateRootIsolate(); + +} + +Dart_Isolate DartIsolate::DartIsolateGroupCreateCallback( + const char* advisory_script_uri, + const char* advisory_script_entrypoint, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + std::shared_ptr* parent_isolate_data, + char** error) +{ + if (parent_isolate_data == nullptr && + strcmp(advisory_script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) + { + // The VM attempts to start the VM service for us on |Dart_Initialize|. In + // such a case, the callback data will be null and the script URI will be + // DART_VM_SERVICE_ISOLATE_NAME. In such cases, we just create the service + // isolate like normal but dont hold a reference to it at all. We also start + // this isolate since we will never again reference it from the engine. + return DartCreateAndStartServiceIsolate(package_root, + package_config, + flags, + error + ); + } + + //DartIsolateGroupData& parent_group_data = + // (*parent_isolate_data)->GetIsolateGroupData(); + + //auto isolate_group_data = new DartIsolateGroupData( + // //parent_group_data.GetSettings(), + // //parent_group_data.GetIsolateSnapshot(), + // advisory_script_uri, + // advisory_script_entrypoint, + // //parent_group_data.GetChildIsolatePreparer(), + // //parent_group_data.GetIsolateCreateCallback(), + // p//arent_group_data.GetIsolateShutdownCallback()))); + + //TaskRunners null_task_runners(advisory_script_uri, + // /* platform= */ nullptr, /* raster= */ nullptr, + // /* ui= */ nullptr, + // /* io= */ nullptr); + + //auto isolate_data = std::make_unique>( + // std::shared_ptr(new DartIsolate( + // (*isolate_group_data)->GetSettings(), // settings + // null_task_runners, // task_runners + // fml::WeakPtr{}, // snapshot_delegate + // fml::WeakPtr{}, // io_manager + // fml::RefPtr{}, // unref_queue + // fml::WeakPtr{}, // image_decoder + // advisory_script_uri, // advisory_script_uri + // advisory_script_entrypoint, // advisory_script_entrypoint + // false))); // is_root_isolate + + //Dart_Isolate vm_isolate = CreateDartIsolateGroup( + // std::move(isolate_group_data), std::move(isolate_data), flags, error); + + if (*error) { + std::cout << "CreateDartIsolateGroup failed: " << error; + } + + return vm_isolate; +} + +// |Dart_IsolateInitializeCallback| +bool DartIsolate::DartIsolateInitializeCallback(void** child_callback_data, char** error) { + Dart_Isolate isolate = Dart_CurrentIsolate(); + if (isolate == nullptr) { + *error = _strdup("Isolate should be available in initialize callback."); + std::cout << *error; + return false; + } + + auto* isolate_group_data = + static_cast*>( + Dart_CurrentIsolateGroupData()); + + TaskRunners null_task_runners((*isolate_group_data)->GetAdvisoryScriptURI(), + /* platform= */ nullptr, /* raster= */ nullptr, + /* ui= */ nullptr, + /* io= */ nullptr); + + auto embedder_isolate = std::make_unique>( + std::shared_ptr(new DartIsolate( + (*isolate_group_data)->GetSettings(), // settings + null_task_runners, // task_runners + fml::WeakPtr{}, // snapshot_delegate + fml::WeakPtr{}, // io_manager + fml::RefPtr{}, // unref_queue + fml::WeakPtr{}, // image_decoder + (*isolate_group_data)->GetAdvisoryScriptURI(), // advisory_script_uri + (*isolate_group_data) + ->GetAdvisoryScriptEntrypoint(), // advisory_script_entrypoint + false))); // is_root_isolate + + // root isolate should have been created via CreateRootIsolate + if (!InitializeIsolate(*embedder_isolate, isolate, error)) { + return false; + } + + // The ownership of the embedder object is controlled by the Dart VM. So the + // only reference returned to the caller is weak. + *child_callback_data = embedder_isolate.release(); + + Dart_EnterIsolate(isolate); + return true; +} + +Dart_Isolate DartIsolate::CreateDartIsolateGroup( + std::unique_ptr> isolate_group_data, + std::unique_ptr> isolate_data, + Dart_IsolateFlags* flags, + char** error) { + + // Create the Dart VM isolate and give it the embedder object as the baton. + Dart_Isolate isolate = Dart_CreateIsolateGroup( + (*isolate_group_data)->GetAdvisoryScriptURI().c_str(), + (*isolate_group_data)->GetAdvisoryScriptEntrypoint().c_str(), + (*isolate_group_data)->GetIsolateSnapshot()->GetDataMapping(), + (*isolate_group_data)->GetIsolateSnapshot()->GetInstructionsMapping(), + flags, isolate_group_data.get(), isolate_data.get(), error); + + if (isolate == nullptr) { + return nullptr; + } + + // Ownership of the isolate data objects has been transferred to the Dart VM. + std::shared_ptr embedder_isolate(*isolate_data); + isolate_group_data.release(); + isolate_data.release(); + + if (!InitializeIsolate(std::move(embedder_isolate), isolate, error)) { + return nullptr; + } + + return isolate; +} + +bool DartIsolate::InitializeIsolate( + std::shared_ptr embedder_isolate, + Dart_Isolate isolate, + char** error) { + if (!embedder_isolate->Initialize(isolate)) { + *error = strdup("Embedder could not initialize the Dart isolate."); + std::cout << *error; + return false; + } + + if (!embedder_isolate->LoadLibraries()) { + *error = strdup( + "Embedder could not load libraries in the new Dart isolate."); + std::cout << *error; + return false; + } + + // Root isolates will be setup by the engine and the service isolate (which is + // also a root isolate) by the utility routines in the VM. However, secondary + // isolates will be run by the VM if they are marked as runnable. + if (!embedder_isolate->IsRootIsolate()) { + auto child_isolate_preparer = + embedder_isolate->GetIsolateGroupData().GetChildIsolatePreparer(); + //FML_DCHECK(child_isolate_preparer); + if (!child_isolate_preparer(embedder_isolate.get())) { + *error = _strdup("Could not prepare the child isolate to run."); + std::cout << *error; + return false; + } + } + + return true; +} + +// |Dart_IsolateShutdownCallback| +void DartIsolate::DartIsolateShutdownCallback( + std::shared_ptr* isolate_group_data, + std::shared_ptr* isolate_data) { + isolate_data->get()->OnShutdownCallback(); +} + +// |Dart_IsolateGroupCleanupCallback| +void DartIsolate::DartIsolateGroupCleanupCallback( + std::shared_ptr* isolate_data) { + delete isolate_data; +} + +// |Dart_IsolateCleanupCallback| +void DartIsolate::DartIsolateCleanupCallback( + std::shared_ptr* isolate_group_data, + std::shared_ptr* isolate_data) { + delete isolate_data; +} \ No newline at end of file diff --git a/DartTest2/DartIsolate.h b/DartTest2/DartIsolate.h new file mode 100644 index 0000000..7119cdf --- /dev/null +++ b/DartTest2/DartIsolate.h @@ -0,0 +1,111 @@ +#pragma once + +#include + +#include "include/dart_api.h" + +class DartIsolateGroupData; + +class DartIsolate { +public: + enum class Phase { + //-------------------------------------------------------------------------- + /// The initial phase of all Dart isolates. This is an internal phase and + /// callers can never get a reference to a Dart isolate in this phase. + /// + Unknown, + //-------------------------------------------------------------------------- + /// The Dart isolate has been created but none of the library tag or message + /// handers have been set yet. The is an internal phase and callers can + /// never get a reference to a Dart isolate in this phase. + /// + Uninitialized, + //-------------------------------------------------------------------------- + /// The Dart isolate has been been fully initialized but none of the + /// libraries referenced by that isolate have been loaded yet. This is an + /// internal phase and callers can never get a reference to a Dart isolate + /// in this phase. + /// + Initialized, + //-------------------------------------------------------------------------- + /// The isolate has been fully initialized and is waiting for the caller to + /// associate isolate snapshots with the same. The isolate will only be + /// ready to execute Dart code once one of the `Prepare` calls are + /// successfully made. + /// + LibrariesSetup, + //-------------------------------------------------------------------------- + /// The isolate is fully ready to start running Dart code. Callers can + /// transition the isolate to the next state by calling the `Run` or + /// `RunFromLibrary` methods. + /// + Ready, + //-------------------------------------------------------------------------- + /// The isolate is currently running Dart code. + /// + Running, + //-------------------------------------------------------------------------- + /// The isolate is no longer running Dart code and is in the middle of being + /// collected. This is in internal phase and callers can never get a + /// reference to a Dart isolate in this phase. + /// + Shutdown, + }; + + DartIsolate(); + + bool Initialize(dartIsolate); + + static void DartIsolateGroupCleanupCallback( + std::shared_ptr* isolate_group_data + ); + + static Dart_Isolate DartIsolateGroupCreateCallback( + const char* advistory_script_uri, + const char* advisory_script_entrypoint, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + std::shared_ptr* parent_isolate_group, + char** error + ); + + static bool DartIsolateInitializeCallback(void** child_callback_data, + char** error); + + static Dart_Isolate DartCreateAndStartServiceIsolate( + const char* packageRoot, + const char* packageConfig, + Dart_IsolateFlags* flags, + char** error); + + static Dart_Isolate CreateDartIsolateGroup( + std::unique_ptr> isolate_group_data, + std::unique_ptr> isolate_data, + Dart_IsolateFlags* flags, + char** error); + + static bool InitializeIsolate(std::shared_ptr embedder_isolate, + Dart_Isolate isolate, + char** error); + + // |Dart_IsolateShutdownCallback| + static void DartIsolateShutdownCallback( + std::shared_ptr* isolate_group_data, + std::shared_ptr* isolate_data); + + // |Dart_IsolateCleanupCallback| + static void DartIsolateCleanupCallback( + std::shared_ptr* isolate_group_data, + std::shared_ptr* isolate_data); + + // |Dart_IsolateGroupCleanupCallback| + static void DartIsolateGroupCleanupCallback( + std::shared_ptr* isolate_group_data); + +private: + static DartIsolate* CreateRootIsolate(); + + Phase _phase; + Dart_Isolate _isolate; +}; \ No newline at end of file diff --git a/DartTest2/DartIsolateGroupData.cpp b/DartTest2/DartIsolateGroupData.cpp new file mode 100644 index 0000000..e69de29 diff --git a/DartTest2/DartIsolateGroupData.h b/DartTest2/DartIsolateGroupData.h new file mode 100644 index 0000000..a9b5760 --- /dev/null +++ b/DartTest2/DartIsolateGroupData.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +class DartIsolateGroupData +{ +public: + DartIsolateGroupData( + std::string advisoryScriptUri, + std::string advisoryScriptEntryPoint + ); + +private: + std::string _advisoryScriptUri; + std::string _advisoryScriptEntryPoint; + +}; \ No newline at end of file diff --git a/DartTest2/DartTest2.cpp b/DartTest2/DartTest2.cpp index b82607d..6878590 100644 --- a/DartTest2/DartTest2.cpp +++ b/DartTest2/DartTest2.cpp @@ -9,14 +9,9 @@ #include "include/dart_api.h" #include "include/dart_tools_api.h" +#include "include/bin/dart_io_api.h" -#include "bin/dfe.h" -#include "bin/platform.h" -#include "bin/vmservice_impl.h" -#include "bin/isolate_data.h" -#include "bin/utils.h" -#include "bin/eventhandler.h" -#include "bin/thread.h" +#include "DartIsolate.h" using namespace dart::bin; @@ -89,36 +84,6 @@ Dart_Handle FilePathFromUri(Dart_Handle script, Dart_Handle core_library) return Dart_Invoke(core_library, Dart_NewStringFromCString("_filePathFromUri"), 1, args); } -Dart_Handle ReadSource(Dart_Handle script, Dart_Handle core_library) -{ - Dart_Handle script_path = FilePathFromUri(script, core_library); - if (Dart_IsError(script_path)) - return script_path; - - const char* script_path_str; - Dart_StringToCString(script_path, &script_path_str); - - FILE* file = nullptr; - fopen_s(&file, script_path_str, "r"); - if (file == nullptr) - return Dart_Error("Unable to read file '%s'", script_path_str); - - fseek(file, 0, SEEK_END); - long length = ftell(file); - fseek(file, 0, SEEK_SET); - - char* buffer = new char[length + 1]; - size_t read = fread(buffer, 1, length, file); - fclose(file); - buffer[read] = '\0'; - - Dart_Handle source = Dart_NewStringFromCString(buffer); - - delete[] buffer; - - return source; -} - Dart_Handle ResolveScript(const char* script, Dart_Handle core_library) { const int kNumArgs = 1; @@ -150,13 +115,6 @@ Dart_Handle LibraryTagHandler(Dart_LibraryTag tag, Dart_Handle library, Dart_Han return Dart_Null(); } - -bool IsServiceIsolateURL(const char* url_name) -{ - return url_name != nullptr && - std::string(url_name) == DART_VM_SERVICE_ISOLATE_NAME; -} - static Dart_Isolate CreateAndSetupKernelIsolate(const char* script_uri, const char* main, const char* package_root, @@ -183,11 +141,7 @@ static Dart_Isolate CreateAndSetupKernelIsolate(const char* script_uri, delete isolate_data; return NULL; } - //kernel_isolate_is_running = true; - - //return IsolateSetupHelper(isolate, false, uri, package_root, packages_config, - // false, flags, error, exit_code); - + Dart_EnterScope(); Dart_Handle result = Dart_SetLibraryTagHandler(LibraryTagHandler); @@ -270,6 +224,7 @@ Dart_Isolate CreateIsolate(bool isMainIsolate, const char* script, const char* m } DartUtils::SetupServiceLoadPort(); + DartUtils::SetupPackageRoot(packageRoot, packageConfig); if (!dfe.CanUseDartFrontend()) { goto fail; } @@ -409,10 +364,25 @@ int main(int argc, const char** argv) params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; params.vm_snapshot_data = kDartVmSnapshotData; params.vm_snapshot_instructions = kDartVmSnapshotInstructions; - params.create = IsolateCreateCallback; - params.shutdown = IsolateShutdownCallback; + params.create_group = reinterpret_cast( + DartIsolate::DartIsolateGroupCreateCallback + ); + params.cleanup_group = reinterpret_cast( + DartIsolate::DartIsolateGroupCleanupCallback + ); + params.initialize_isolate = reinterpret_cast( + DartIsolate::DartIsolateInitializeCallback + ); + params.shutdown_isolate = reinterpret_cast( + DartIsolate::DartIsolateShutdownCallback + ); + params.cleanup_isolate = reinterpret_cast ( + DartIsolate::DartIsolateCleanupCallback + ); + params.entropy_source = dart::bin::GetEntropy; + params.start_kernel_isolate = true; -// dfe.UseDartFrontend() && dfe.CanUseDartFrontend(); + char* initError = Dart_Initialize(¶ms); if (initError) { @@ -427,7 +397,7 @@ int main(int argc, const char** argv) char* error; int exitCode; - Dart_Isolate isolate = CreateIsolate(true, "hello_world.dart", "main", nullptr, nullptr, &isolateFlags, &error, &exitCode); + Dart_Isolate isolate = CreateIsolate(true, "hello_world.dart", "main", nullptr, "c:\\Uses\\jeff\\Projects\\DartTest2\\DartTest2\\.packages", &isolateFlags, &error, &exitCode); Dart_EnterIsolate(isolate); Dart_EnterScope(); diff --git a/DartTest2/DartTest2.vcxproj b/DartTest2/DartTest2.vcxproj index fce688f..5c7fc75 100644 --- a/DartTest2/DartTest2.vcxproj +++ b/DartTest2/DartTest2.vcxproj @@ -23,32 +23,32 @@ {489F4F6A-B87F-4D19-963A-C7AE926BA74A} Win32Proj DartTest2 - 10.0.17763.0 + 10.0 Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode @@ -158,10 +158,16 @@ + + + + + + Create diff --git a/DartTest2/DartTest2.vcxproj.filters b/DartTest2/DartTest2.vcxproj.filters index fa1b8f2..cefe695 100644 --- a/DartTest2/DartTest2.vcxproj.filters +++ b/DartTest2/DartTest2.vcxproj.filters @@ -21,6 +21,15 @@ Header Files + + Source Files + + + Source Files + + + Source Files + @@ -29,6 +38,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + diff --git a/DartTest2/hello_world.dart b/DartTest2/hello_world.dart index 01f8810..f453f66 100644 --- a/DartTest2/hello_world.dart +++ b/DartTest2/hello_world.dart @@ -1,7 +1,11 @@ library mylib; -void simplePrint(String s) native "SimplePrint"; +import 'package:vector_math/vector_math.dart'; +import 'package:dart_test/natives.dart'; void main() { simplePrint("hello world"); -} \ No newline at end of file + + var vec = Vector2.all(1.0); + simplePrint("Value of vector i $vec"); +} diff --git a/DartTest2/lib/natives.dart b/DartTest2/lib/natives.dart new file mode 100644 index 0000000..97d4c83 --- /dev/null +++ b/DartTest2/lib/natives.dart @@ -0,0 +1,3 @@ +library dart_test; + +void simplePrint(String s) native "SimplePrint"; diff --git a/DartTest2/pubspec.lock b/DartTest2/pubspec.lock new file mode 100644 index 0000000..fdb7a1c --- /dev/null +++ b/DartTest2/pubspec.lock @@ -0,0 +1,12 @@ +# Generated by pub +# See https://www.dartlang.org/tools/pub/glossary#lockfile +packages: + vector_math: + dependency: "direct main" + description: + name: vector_math + url: "https://pub.dartlang.org/" + source: hosted + version: "2.0.8" +sdks: + dart: ">=2.0.0 <3.0.0" diff --git a/DartTest2/pubspec.yaml b/DartTest2/pubspec.yaml new file mode 100644 index 0000000..de751ba --- /dev/null +++ b/DartTest2/pubspec.yaml @@ -0,0 +1,7 @@ +name: dart_test +environment: + sdk: '>=2.0.0 <3.0.0' + +dependencies: + vector_math: any + \ No newline at end of file diff --git a/README.md b/README.md index 041495d..8e40544 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,11 @@ - - -How to use this -=============== +# How to use this You can clone this repo and pull out the dart directory which contains all the headers and libraries you'll need (see Other Notes about some gotchas with these libs). -DartTest2/DartTest2.cpp does all of the embedding work. Note: -- I will be working on simplifying this as much as I can and making the code style +DartTest2/DartTest2.cpp does all of the embedding work. Note: + +- I will be working on simplifying this as much as I can and making the code style consistent. Right now it's all over the place. - I will be researching what's necessary to perform this embedding `without` using Dart_RunLoop, since in a game (my target) I can't just have that hang forever. I will @@ -16,14 +14,15 @@ DartTest2/DartTest2.cpp does all of the embedding work. Note: to check. Other Notes - - - This is taken from main.cc in runtime/bin which is complicated because it supports all the various + +- This is taken from main.cc in runtime/bin which is complicated because it supports all the various ways of booting the dart runtime in AOT, and other modes. I would like to see how to accomplish that moving forward - - The startup time is high... I'm not sure why +- The startup time is high... I'm not sure why +# How I did this -How I did this -=============== +_Updated 7/21/2020_ Dart doesn't have anything available that makes embedding easy. The dart.lib and header files included in the SDK are for creating extensions, not for embedding, so unfortunately, @@ -34,25 +33,31 @@ you'll have to build it yourself. Get the Dart SDK source according to the instructions provided at the Dart home page: https://github.com/dart-lang/sdk/wiki/Building -If you're using Visual Studio 2017 Community (like I am) you'll have to trick depot_tools into using it. Set the following environment variables: +If you're using Visual Studio 2019 Community (like I am) you'll have to trick depot_tools into using it. Set the following environment variables: + - set GYP_MSVS_VERSION=2017 - set DEPOT_TOOLS_WIN_TOOLCHAIN=0 +- GYP_MSVS_OVERRIDE_PATH=c:\Program Files (x86)\Microsoft Visual Studio\2019\Community\ + +Also make sure that you are using Python 2 over Python 3. The wiki has instructions on how to set the environment, but you can just make sure +Python 2 is on your path before Python 3 -## Build the SDK -Just in case, let's make sure everything builds properly. +## Build the SDK + +Just in case, let's make sure everything builds properly. As of this writing, this just involves doing tools/build.py --mode=release create_sdk ## Modify some GN files Dart needs a lot of extra stuff on top of the VM to get a lot of the embedding story -working. Instead of trying to figure out what was necessary and not, I basically created -a library that is all of dart.exe minus "main.cc" and called it "dart_lib". To do this: +working. Instead of trying to figure out what was necessary and not, I basically created +a library that is all of dart.exe minus "main.cc" and called it "dart_lib". To do this: - Edit runtime/bin/BUILD.gn and copy the template "dart_executable" and the subsequent target "dart" -- Rename the template "dart_runtime_library" change the "dart" target to "dart_lib" -- Add "complete_static_lib = true" to the "static_lib" directive in your new +- Rename the template "dart_runtime_library" change the "dart" target to "dart_lib" +- Add "complete_static_lib = true" to the "static_lib" directive in your new "dart_runtime_library template." This causes GN to bring all of the dependencies into one static library instead of saving them for a final executable. - Regenerate your ninja files for Dart (buildtools\win\gn.exe gen out\DebugX64) @@ -61,18 +66,17 @@ a library that is all of dart.exe minus "main.cc" and called it "dart_lib". To - ninja dart_lib - The new library will be in out\DebugX64\obj\runtime\bin - I copied over a bunch of header files into the dart directory locally. You could just - reference them directly if you had the dart directory in your include path. You can + reference them directly if you had the dart directory in your include path. You can look in theh repo and see what I needed to copy other than the dart_api headers +# Other Notes -Other Notes -=========== I made other changes to GN files to suit my development style. For example, I no longer use the statically linked C runtime when I can avoid it, but dart does. If you are building this for yourself, you may need to change these settings to suit your needs. These changes are made in build/config/compiler/BUILD.gn -Like this? -========== -Follow me [(@fuzzybinary)](http://twitter.com/fuzzybinary) on twitter and let me know. I'd love to hear from you! \ No newline at end of file +# Like this? + +Follow me [(@fuzzybinary)](http://twitter.com/fuzzybinary) on twitter and let me know. I'd love to hear from you! diff --git a/dart/include/bin/dart_io_api.h b/dart/include/bin/dart_io_api.h new file mode 100644 index 0000000..07a384c --- /dev/null +++ b/dart/include/bin/dart_io_api.h @@ -0,0 +1,63 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#ifndef RUNTIME_INCLUDE_BIN_DART_IO_API_H_ +#define RUNTIME_INCLUDE_BIN_DART_IO_API_H_ + +#include "include/dart_tools_api.h" + +namespace dart { +namespace bin { + +// Bootstraps 'dart:io'. +void BootstrapDartIo(); + +// Cleans up 'dart:io'. +void CleanupDartIo(); + +// Lets dart:io know where the system temporary directory is located. +// Currently only wired up on Android. +void SetSystemTempDirectory(const char* system_temp); + +// Tells the system whether to capture Stdout events. +void SetCaptureStdout(bool value); + +// Tells the system whether to capture Stderr events. +void SetCaptureStderr(bool value); + +// Should Stdout events be captured? +bool ShouldCaptureStdout(); + +// Should Stderr events be captured? +bool ShouldCaptureStderr(); + +// Set the executable name used by Platform.executable. +void SetExecutableName(const char* executable_name); + +// Set the arguments used by Platform.executableArguments. +void SetExecutableArguments(int script_index, char** argv); + +// Set dart:io implementation specific fields of Dart_EmbedderInformation. +void GetIOEmbedderInformation(Dart_EmbedderInformation* info); + +// Generates 'length' random bytes into 'buffer'. Returns true on success +// and false on failure. This is appropriate to assign to +// Dart_InitializeParams.entropy_source. +bool GetEntropy(uint8_t* buffer, intptr_t length); + +// Performs a lookup of the I/O Dart_NativeFunction with a specified 'name' and +// 'argument_count'. Returns NULL if no I/O native function with a matching +// name and parameter count is found. +Dart_NativeFunction LookupIONative(Dart_Handle name, + int argument_count, + bool* auto_setup_scope); + +// Returns the symbol for I/O native function 'nf'. Returns NULL if 'nf' is not +// a valid I/O native function. +const uint8_t* LookupIONativeSymbol(Dart_NativeFunction nf); + +} // namespace bin +} // namespace dart + +#endif // RUNTIME_INCLUDE_BIN_DART_IO_API_H_ diff --git a/dart/include/dart_api.h b/dart/include/dart_api.h index 5ac0f25..8c6afd4 100644 --- a/dart/include/dart_api.h +++ b/dart/include/dart_api.h @@ -15,6 +15,16 @@ * This reference is generated from the header include/dart_api.h. */ +/* __STDC_FORMAT_MACROS has to be defined before including to + * enable platform independent printf format specifiers. */ +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include +#include +#include + #ifdef __cplusplus #define DART_EXTERN_C extern "C" #else @@ -24,32 +34,12 @@ #if defined(__CYGWIN__) #error Tool chain and platform not supported. #elif defined(_WIN32) -// Define bool if necessary. -#ifndef __cplusplus -typedef unsigned __int8 bool; -#endif -// Define integer types. -typedef signed __int8 int8_t; -typedef signed __int16 int16_t; -typedef signed __int32 int32_t; -typedef signed __int64 int64_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; #if defined(DART_SHARED_LIB) #define DART_EXPORT DART_EXTERN_C __declspec(dllexport) #else #define DART_EXPORT DART_EXTERN_C #endif #else -/* __STDC_FORMAT_MACROS has to be defined before including to - * enable platform independent printf format specifiers. */ -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif -#include -#include #if __GNUC__ >= 4 #if defined(DART_SHARED_LIB) #define DART_EXPORT \ @@ -70,8 +60,6 @@ typedef unsigned __int64 uint64_t; #define DART_WARN_UNUSED_RESULT #endif -#include - /* * ======= * Handles @@ -88,9 +76,10 @@ typedef unsigned __int64 uint64_t; * current isolate may be NULL, in which case no isolate is ready to * execute. Most of the Dart apis require there to be a current * isolate in order to function without error. The current isolate is - * set by any call to Dart_CreateIsolate or Dart_EnterIsolate. + * set by any call to Dart_CreateIsolateGroup or Dart_EnterIsolate. */ typedef struct _Dart_Isolate* Dart_Isolate; +typedef struct _Dart_IsolateGroup* Dart_IsolateGroup; /** * An object reference managed by the Dart VM garbage collector. @@ -176,7 +165,7 @@ typedef struct _Dart_Isolate* Dart_Isolate; * 2 intptr_t* length = 0; * 3 result = Dart_StringLength(arg, &length); * 4 if (Dart_IsError(result)) { - * 5 return result + * 5 return result; * 6 } * 7 return Dart_NewBoolean(length > 100); * 8 } @@ -254,6 +243,8 @@ typedef struct _Dart_Isolate* Dart_Isolate; typedef struct _Dart_Handle* Dart_Handle; typedef Dart_Handle Dart_PersistentHandle; typedef struct _Dart_WeakPersistentHandle* Dart_WeakPersistentHandle; +// These three structs are versioned by DART_API_DL_MAJOR_VERSION, bump the +// version when changing this struct. typedef void (*Dart_WeakPersistentHandleFinalizer)( void* isolate_callback_data, @@ -386,34 +377,10 @@ DART_EXPORT Dart_Handle Dart_NewUnhandledExceptionError(Dart_Handle exception); * * \param An error handle (See Dart_IsError) * - * \return On success, this function does not return. On failure, an - * error handle is returned. - */ -DART_EXPORT Dart_Handle Dart_PropagateError(Dart_Handle handle); -/* TODO(turnidge): Should this really return an error handle? */ -/* Consider just terminating. */ - -/* Internal routine used for reporting error handles. */ -DART_EXPORT void _Dart_ReportErrorHandle(const char* file, - int line, - const char* handle_string, - const char* error); - -/* TODO(turnidge): Move DART_CHECK_VALID to some sort of dart_utils - * header instead of this header. */ -/** - * Aborts the process if 'handle' is an error handle. - * - * Provided for convenience. + * \return On success, this function does not return. On failure, the + * process is terminated. */ -#define DART_CHECK_VALID(handle) \ - { \ - Dart_Handle __handle = handle; \ - if (Dart_IsError((__handle))) { \ - _Dart_ReportErrorHandle(__FILE__, __LINE__, #handle, \ - Dart_GetError(__handle)); \ - } \ - } +DART_EXPORT void Dart_PropagateError(Dart_Handle handle); /** * Converts an object to a string. @@ -477,8 +444,6 @@ DART_EXPORT void Dart_SetPersistentHandle(Dart_PersistentHandle obj1, /** * Deallocates a persistent handle. - * - * Requires there to be a current isolate. */ DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object); @@ -492,13 +457,16 @@ DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object); * calling Dart_DeleteWeakPersistentHandle. * * If the object becomes unreachable the callback is invoked with the weak - * persistent handle and the peer as arguments. The callback is invoked on the - * thread that has entered the isolate at the time of garbage collection. This - * gives the embedder the ability to cleanup data associated with the object and - * clear out any cached references to the handle. All references to this handle - * after the callback will be invalid. It is illegal to call into the VM from - * the callback. If the handle is deleted before the object becomes unreachable, - * the callback is never invoked. + * persistent handle and the peer as arguments. The callback can be executed + * on any thread, will not have a current isolate, and can only call + * Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle. The callback + * must not call Dart_DeleteWeakPersistentHandle for the handle being finalized, + * as it is automatically deleted by the VM after the callback returns. + * This gives the embedder the ability to cleanup data associated with the + * object and clear out any cached references to the handle. All references to + * this handle after the callback will be invalid. It is illegal to call into + * the VM from the callback. If the handle is deleted before the object becomes + * unreachable, the callback is never invoked. * * Requires there to be a current isolate. * @@ -521,9 +489,11 @@ Dart_NewWeakPersistentHandle(Dart_Handle object, Dart_WeakPersistentHandleFinalizer callback); DART_EXPORT void Dart_DeleteWeakPersistentHandle( - Dart_Isolate isolate, Dart_WeakPersistentHandle object); +DART_EXPORT void Dart_UpdateExternalSize(Dart_WeakPersistentHandle object, + intptr_t external_allocation_size); + /* * ========================== * Initialization and Globals @@ -553,7 +523,7 @@ typedef struct { * for each part. */ -#define DART_FLAGS_CURRENT_VERSION (0x0000000b) +#define DART_FLAGS_CURRENT_VERSION (0x0000000c) typedef struct { int32_t version; @@ -562,10 +532,9 @@ typedef struct { bool use_osr; bool obfuscate; Dart_QualifiedFunctionName* entry_points; - bool use_bare_instructions; bool load_vmservice_library; - bool unsafe_trust_strong_mode_types; bool copy_parent_code; + bool null_safety; } Dart_IsolateFlags; /** @@ -578,7 +547,7 @@ DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags); * * This callback, provided by the embedder, is called when the VM * needs to create an isolate. The callback should create an isolate - * by calling Dart_CreateIsolate and load any scripts required for + * by calling Dart_CreateIsolateGroup and load any scripts required for * execution. * * This callback may be called on a different thread than the one @@ -587,7 +556,7 @@ DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags); * When the function returns NULL, it is the responsibility of this * function to ensure that Dart_ShutdownIsolate has been called if * required (for example, if the isolate was created successfully by - * Dart_CreateIsolate() but the root library fails to load + * Dart_CreateIsolateGroup() but the root library fails to load * successfully, then the function should call Dart_ShutdownIsolate * before returning). * @@ -597,7 +566,7 @@ DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags); * freed. * * \param script_uri The uri of the main source file or snapshot to load. - * Either the URI of the parent isolate set in Dart_CreateIsolate for + * Either the URI of the parent isolate set in Dart_CreateIsolateGroup for * Isolate.spawn, or the argument to Isolate.spawnUri canonicalized by the * library tag handler of the parent isolate. * The callback is responsible for loading the program by a call to @@ -606,33 +575,63 @@ DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags); * eventually run. This is provided for advisory purposes only to * improve debugging messages. The main function is not invoked by * this function. - * \param package_root The package root path for this isolate to resolve - * package imports against. Only one of package_root and package_map - * parameters is non-NULL. If neither parameter is passed the package - * resolution of the parent isolate should be used. - * \param package_map The package map for this isolate to resolve package - * imports against. The array contains alternating keys and values, - * terminated by a NULL key. Only one of package_root and package_map - * parameters is non-NULL. If neither parameter is passed the package - * resolution of the parent isolate should be used. + * \param package_root Ignored. + * \param package_config Uri of the package configuration file (either in format + * of .packages or .dart_tool/package_config.json) for this isolate + * to resolve package imports against. If this parameter is not passed the + * package resolution of the parent isolate should be used. * \param flags Default flags for this isolate being spawned. Either inherited * from the spawning isolate or passed as parameters when spawning the * isolate from Dart code. - * \param callback_data The callback data which was passed to the - * parent isolate when it was created by calling Dart_CreateIsolate(). + * \param isolate_data The isolate data which was passed to the + * parent isolate when it was created by calling Dart_CreateIsolateGroup(). * \param error A structure into which the embedder can place a * C string containing an error message in the case of failures. * * \return The embedder returns NULL if the creation and * initialization was not successful and the isolate if successful. */ -typedef Dart_Isolate (*Dart_IsolateCreateCallback)(const char* script_uri, - const char* main, - const char* package_root, - const char* package_config, - Dart_IsolateFlags* flags, - void* callback_data, - char** error); +typedef Dart_Isolate (*Dart_IsolateGroupCreateCallback)( + const char* script_uri, + const char* main, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + void* isolate_data, + char** error); + +/** + * An isolate initialization callback function. + * + * This callback, provided by the embedder, is called when the VM has created an + * isolate within an existing isolate group (i.e. from the same source as an + * existing isolate). + * + * The callback should setup native resolvers and might want to set a custom + * message handler via [Dart_SetMessageNotifyCallback] and mark the isolate as + * runnable. + * + * This callback may be called on a different thread than the one + * running the parent isolate. + * + * When the function returns `false`, it is the responsibility of this + * function to ensure that `Dart_ShutdownIsolate` has been called. + * + * When the function returns `false`, the function should set *error to + * a malloc-allocated buffer containing a useful error message. The + * caller of this function (the VM) will make sure that the buffer is + * freed. + * + * \param child_isolate_data The callback data to associate with the new + * child isolate. + * \param error A structure into which the embedder can place a + * C string containing an error message in the case the initialization fails. + * + * \return The embedder returns true if the initialization was successful and + * false otherwise (in which case the VM will terminate the isolate). + */ +typedef bool (*Dart_InitializeIsolateCallback)(void** child_isolate_data, + char** error); /** * An isolate unhandled exception callback function. @@ -651,11 +650,13 @@ typedef void (*Dart_IsolateUnhandledExceptionCallback)(Dart_Handle error); * This function should be used to dispose of native resources that * are allocated to an isolate in order to avoid leaks. * - * \param callback_data The same callback data which was passed to the - * isolate when it was created. - * + * \param isolate_group_data The same callback data which was passed to the + * isolate group when it was created. + * \param isolate_data The same callback data which was passed to the isolate + * when it was created. */ -typedef void (*Dart_IsolateShutdownCallback)(void* callback_data); +typedef void (*Dart_IsolateShutdownCallback)(void* isolate_group_data, + void* isolate_data); /** * An isolate cleanup callback function. @@ -667,11 +668,28 @@ typedef void (*Dart_IsolateShutdownCallback)(void* callback_data); * This function should be used to dispose of native resources that * are allocated to an isolate in order to avoid leaks. * - * \param callback_data The same callback data which was passed to the - * isolate when it was created. + * \param isolate_group_data The same callback data which was passed to the + * isolate group when it was created. + * \param isolate_data The same callback data which was passed to the isolate + * when it was created. + */ +typedef void (*Dart_IsolateCleanupCallback)(void* isolate_group_data, + void* isolate_data); + +/** + * An isolate group cleanup callback function. + * + * This callback, provided by the embedder, is called after the vm + * shuts down an isolate group. + * + * This function should be used to dispose of native resources that + * are allocated to an isolate in order to avoid leaks. + * + * \param isolate_group_data The same callback data which was passed to the + * isolate group when it was created. * */ -typedef void (*Dart_IsolateCleanupCallback)(void* callback_data); +typedef void (*Dart_IsolateGroupCleanupCallback)(void* isolate_group_data); /** * A thread death callback function. @@ -739,7 +757,31 @@ typedef Dart_Handle (*Dart_GetVMServiceAssetsArchive)(); * The current version of the Dart_InitializeFlags. Should be incremented every * time Dart_InitializeFlags changes in a binary incompatible way. */ -#define DART_INITIALIZE_PARAMS_CURRENT_VERSION (0x00000003) +#define DART_INITIALIZE_PARAMS_CURRENT_VERSION (0x00000004) + +/** Forward declaration */ +struct Dart_CodeObserver; + +/** + * Callback provided by the embedder that is used by the VM to notify on code + * object creation, *before* it is invoked the first time. + * This is useful for embedders wanting to e.g. keep track of PCs beyond + * the lifetime of the garbage collected code objects. + * Note that an address range may be used by more than one code object over the + * lifecycle of a process. Clients of this function should record timestamps for + * these compilation events and when collecting PCs to disambiguate reused + * address ranges. + */ +typedef void (*Dart_OnNewCodeCallback)(struct Dart_CodeObserver* observer, + const char* name, + uintptr_t base, + uintptr_t size); + +typedef struct Dart_CodeObserver { + void* data; + + Dart_OnNewCodeCallback on_new_code; +} Dart_CodeObserver; /** * Describes how to initialize the VM. Used with Dart_Initialize. @@ -752,23 +794,32 @@ typedef Dart_Handle (*Dart_GetVMServiceAssetsArchive)(); * \param instructions_snapshot A buffer containing a snapshot of precompiled * instructions, or NULL if no snapshot is provided. If provided, the buffer * must remain valid until Dart_Cleanup returns. - * \param create A function to be called during isolate creation. - * See Dart_IsolateCreateCallback. - * \param shutdown A function to be called when an isolate is shutdown. + * \param initialize_isolate A function to be called during isolate + * initialization inside an existing isolate group. + * See Dart_InitializeIsolateCallback. + * \param create_group A function to be called during isolate group creation. + * See Dart_IsolateGroupCreateCallback. + * \param shutdown A function to be called right before an isolate is shutdown. * See Dart_IsolateShutdownCallback. - * \param cleanup A function to be called after an isolate is shutdown. + * \param cleanup A function to be called after an isolate was shutdown. * See Dart_IsolateCleanupCallback. + * \param cleanup_group A function to be called after an isolate group is shutdown. + * See Dart_IsolateGroupCleanupCallback. * \param get_service_assets A function to be called by the service isolate when * it requires the vmservice assets archive. * See Dart_GetVMServiceAssetsArchive. + * \param code_observer An external code observer callback function. + * The observer can be invoked as early as during the Dart_Initialize() call. */ typedef struct { int32_t version; const uint8_t* vm_snapshot_data; const uint8_t* vm_snapshot_instructions; - Dart_IsolateCreateCallback create; - Dart_IsolateShutdownCallback shutdown; - Dart_IsolateCleanupCallback cleanup; + Dart_IsolateGroupCreateCallback create_group; + Dart_InitializeIsolateCallback initialize_isolate; + Dart_IsolateShutdownCallback shutdown_isolate; + Dart_IsolateCleanupCallback cleanup_isolate; + Dart_IsolateGroupCleanupCallback cleanup_group; Dart_ThreadExitCallback thread_exit; Dart_FileOpenCallback file_open; Dart_FileReadCallback file_read; @@ -777,6 +828,7 @@ typedef struct { Dart_EntropySource entropy_source; Dart_GetVMServiceAssetsArchive get_service_assets; bool start_kernel_isolate; + Dart_CodeObserver* code_observer; } Dart_InitializeParams; /** @@ -796,6 +848,9 @@ DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_Initialize( * * \return NULL if cleanup is successful. Returns an error message otherwise. * The caller is responsible for freeing the error message. + * + * NOTE: This function must not be called on a thread that was created by the VM + * itself. */ DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_Cleanup(); @@ -807,12 +862,18 @@ DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_Cleanup(); * * \return NULL if successful. Returns an error message otherwise. * The caller is responsible for freeing the error message. + * + * NOTE: This call does not store references to the passed in c-strings. */ DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_SetVMFlags(int argc, const char** argv); /** - * Returns true if the named VM flag is set. + * Returns true if the named VM flag is of boolean type, specified, and set to + * true. + * + * \param flag_name The name of the flag without leading punctuation + * (example: "enable_asserts"). */ DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name); @@ -834,19 +895,22 @@ DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name); * Requires there to be no current isolate. * * \param script_uri The main source file or snapshot this isolate will load. - * The VM will provide this URI to the Dart_IsolateCreateCallback when a child + * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a child * isolate is created by Isolate.spawn. The embedder should use a URI that * allows it to load the same program into such a child isolate. - * \param main The name of the main entry point this isolate will run. Provided - * only for advisory purposes to improve debugging messages. Typically either - * 'main' or the name of the function passed to Isolate.spawn. + * \param name A short name for the isolate to improve debugging messages. + * Typically of the format 'foo.dart:main()'. * \param isolate_snapshot_data * \param isolate_snapshot_instructions Buffers containing a snapshot of the * isolate or NULL if no snapshot is provided. If provided, the buffers must * remain valid until the isolate shuts down. * \param flags Pointer to VM specific flags or NULL for default flags. - * \param callback_data Embedder data. This data will be passed to - * the Dart_IsolateCreateCallback when new isolates are spawned from + * \param isolate_group_data Embedder group data. This data can be obtained + * by calling Dart_IsolateGroupData and will be passed to the + * Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and + * Dart_IsolateGroupCleanupCallback. + * \param isolate_data Embedder data. This data will be passed to + * the Dart_IsolateGroupCreateCallback when new isolates are spawned from * this parent isolate. * \param error Returns NULL if creation is successful, an error message * otherwise. The caller is responsible for calling free() on the error @@ -855,15 +919,14 @@ DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name); * \return The new isolate on success, or NULL if isolate creation failed. */ DART_EXPORT Dart_Isolate -Dart_CreateIsolate(const char* script_uri, - const char* main, - const uint8_t* isolate_snapshot_data, - const uint8_t* isolate_snapshot_instructions, - const uint8_t* shared_data, - const uint8_t* shared_instructions, - Dart_IsolateFlags* flags, - void* callback_data, - char** error); +Dart_CreateIsolateGroup(const char* script_uri, + const char* name, + const uint8_t* isolate_snapshot_data, + const uint8_t* isolate_snapshot_instructions, + Dart_IsolateFlags* flags, + void* isolate_group_data, + void* isolate_data, + char** error); /* TODO(turnidge): Document behavior when there is already a current * isolate. */ @@ -874,18 +937,21 @@ Dart_CreateIsolate(const char* script_uri, * Requires there to be no current isolate. * * \param script_uri The main source file or snapshot this isolate will load. - * The VM will provide this URI to the Dart_IsolateCreateCallback when a child + * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a child * isolate is created by Isolate.spawn. The embedder should use a URI that * allows it to load the same program into such a child isolate. - * \param main The name of the main entry point this isolate will run. Provided - * only for advisory purposes to improve debugging messages. Typically either - * 'main' or the name of the function passed to Isolate.spawn. + * \param name A short name for the isolate to improve debugging messages. + * Typically of the format 'foo.dart:main()'. * \param kernel_buffer * \param kernel_buffer_size A buffer which contains a kernel/DIL program. Must * remain valid until isolate shutdown. * \param flags Pointer to VM specific flags or NULL for default flags. - * \param callback_data Embedder data. This data will be passed to - * the Dart_IsolateCreateCallback when new isolates are spawned from + * \param isolate_group_data Embedder group data. This data can be obtained + * by calling Dart_IsolateGroupData and will be passed to the + * Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and + * Dart_IsolateGroupCleanupCallback. + * \param isolate_data Embedder data. This data will be passed to + * the Dart_IsolateGroupCreateCallback when new isolates are spawned from * this parent isolate. * \param error Returns NULL if creation is successful, an error message * otherwise. The caller is responsible for calling free() on the error @@ -894,13 +960,14 @@ Dart_CreateIsolate(const char* script_uri, * \return The new isolate on success, or NULL if isolate creation failed. */ DART_EXPORT Dart_Isolate -Dart_CreateIsolateFromKernel(const char* script_uri, - const char* main, - const uint8_t* kernel_buffer, - intptr_t kernel_buffer_size, - Dart_IsolateFlags* flags, - void* callback_data, - char** error); +Dart_CreateIsolateGroupFromKernel(const char* script_uri, + const char* name, + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size, + Dart_IsolateFlags* flags, + void* isolate_group_data, + void* isolate_data, + char** error); /** * Shuts down the current isolate. After this call, the current isolate is NULL. * Any current scopes created by Dart_EnterScope will be exited. Invokes the @@ -918,19 +985,37 @@ DART_EXPORT void Dart_ShutdownIsolate(); DART_EXPORT Dart_Isolate Dart_CurrentIsolate(); /** - * Returns the callback data associated with the current Isolate. This data was - * passed to the isolate when it was created. + * Returns the callback data associated with the current isolate. This + * data was set when the isolate got created or initialized. */ DART_EXPORT void* Dart_CurrentIsolateData(); /** - * Returns the callback data associated with the specified Isolate. This data - * was passed to the isolate when it was created. - * The embedder is responsible for ensuring the consistency of this data - * with respect to the lifecycle of an Isolate. + * Returns the callback data associated with the given isolate. This + * data was set when the isolate got created or initialized. */ DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate); +/** + * Returns the current isolate group. Will return NULL if there is no + * current isolate group. + */ +DART_EXPORT Dart_IsolateGroup Dart_CurrentIsolateGroup(); + +/** + * Returns the callback data associated with the current isolate group. This + * data was passed to the isolate group when it was created. + */ +DART_EXPORT void* Dart_CurrentIsolateGroupData(); + +/** + * Returns the callback data associated with the specified isolate group. This + * data was passed to the isolate when it was created. + * The embedder is responsible for ensuring the consistency of this data + * with respect to the lifecycle of an isolate group. + */ +DART_EXPORT void* Dart_IsolateGroupData(Dart_Isolate isolate); + /** * Returns the debugging name for the current isolate. * @@ -939,6 +1024,13 @@ DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate); */ DART_EXPORT Dart_Handle Dart_DebugName(); +/** + * Returns the ID for an isolate which is used to query the service protocol. + * + * It is the responsibility of the caller to free the returned ID. + */ +DART_EXPORT const char* Dart_IsolateServiceId(Dart_Isolate isolate); + /** * Enters an isolate. After calling this function, * the current isolate will be set to the provided isolate. @@ -948,6 +1040,20 @@ DART_EXPORT Dart_Handle Dart_DebugName(); */ DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate); +/** + * Kills the given isolate. + * + * This function has the same effect as dart:isolate's + * Isolate.kill(priority:immediate). + * It can interrupt ordinary Dart code but not native code. If the isolate is + * in the middle of a long running native function, the isolate will not be + * killed until control returns to Dart. + * + * Does not require a current isolate. It is safe to kill the current isolate if + * there is one. + */ +DART_EXPORT void Dart_KillIsolate(Dart_Isolate isolate); + /** * Notifies the VM that the embedder expects to be idle until |deadline|. The VM * may use this time to perform garbage collection or other tasks to avoid @@ -967,6 +1073,20 @@ DART_EXPORT void Dart_NotifyIdle(int64_t deadline); */ DART_EXPORT void Dart_NotifyLowMemory(); +/** + * Starts the CPU sampling profiler. + */ +DART_EXPORT void Dart_StartProfiling(); + +/** + * Stops the CPU sampling profiler. + * + * Note that some profile samples might still be taken after this fucntion + * returns due to the asynchronous nature of the implementation on some + * platforms. + */ +DART_EXPORT void Dart_StopProfiling(); + /** * Notifies the VM that the current thread should not be profiled until a * matching call to Dart_ThreadEnableProfiling is made. @@ -988,6 +1108,16 @@ DART_EXPORT void Dart_ThreadDisableProfiling(); */ DART_EXPORT void Dart_ThreadEnableProfiling(); +/** + * Register symbol information for the Dart VM's profiler and crash dumps. + * + * This consumes the output of //topaz/runtime/dart/profiler_symbols, which + * should be treated as opaque. + */ +DART_EXPORT void Dart_AddSymbols(const char* dso_name, + void* buffer, + intptr_t buffer_size); + /** * Exits an isolate. After this call, Dart_CurrentIsolate will * return NULL. @@ -1006,7 +1136,8 @@ DART_EXPORT void Dart_ExitIsolate(); * the vm isolate on startup and fast initialization of an isolate. * A Snapshot of the heap is created before any dart code has executed. * - * Requires there to be a current isolate. + * Requires there to be a current isolate. Not available in the precompiled + * runtime (check Dart_IsPrecompiledRuntime). * * \param buffer Returns a pointer to a buffer containing the * snapshot. This buffer is scope allocated and is only valid @@ -1367,6 +1498,11 @@ DART_EXPORT uint8_t* Dart_ScopeAllocate(intptr_t size); */ DART_EXPORT Dart_Handle Dart_Null(); +/** + * Is this object null? + */ +DART_EXPORT bool Dart_IsNull(Dart_Handle object); + /** * Returns the empty string object. * @@ -1375,9 +1511,14 @@ DART_EXPORT Dart_Handle Dart_Null(); DART_EXPORT Dart_Handle Dart_EmptyString(); /** - * Is this object null? + * Returns types that are not classes, and which therefore cannot be looked up + * as library members by Dart_GetType. + * + * \return A handle to the dynamic, void or Never type. */ -DART_EXPORT bool Dart_IsNull(Dart_Handle object); +DART_EXPORT Dart_Handle Dart_TypeDynamic(); +DART_EXPORT Dart_Handle Dart_TypeVoid(); +DART_EXPORT Dart_Handle Dart_TypeNever(); /** * Checks if the two objects are equal. @@ -1843,6 +1984,10 @@ DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle str, /** * Gets a UTF-8 encoded representation of a String. * + * Any unpaired surrogate code points in the string will be converted as + * replacement characters (U+FFFD, 0xEF 0xBF 0xBD in UTF-8). If you need + * to preserve unpaired surrogates, use the Dart_StringToUTF16 function. + * * \param str A string. * \param utf8_array Returns the String represented as UTF-8 code * units. This UTF-8 array is scope allocated and is only valid @@ -1940,15 +2085,15 @@ typedef enum { Dart_CoreType_String, } Dart_CoreType_Id; +// TODO(bkonyi): convert this to use nullable types once NNBD is enabled. /** - * Returns a List of the desired length with the desired element type. + * Returns a List of the desired length with the desired legacy element type. * * \param element_type_id The type of elements of the list. - * * \param length The length of the list. * - * \return The List object if no error occurs. Otherwise returns - * an error handle. + * \return The List object if no error occurs. Otherwise returns an error + * handle. */ DART_EXPORT Dart_Handle Dart_NewListOf(Dart_CoreType_Id element_type_id, intptr_t length); @@ -1956,7 +2101,8 @@ DART_EXPORT Dart_Handle Dart_NewListOf(Dart_CoreType_Id element_type_id, /** * Returns a List of the desired length with the desired element type. * - * \param element_type Handle to a type object. E.g., from Dart_GetType. + * \param element_type Handle to a nullable type object. E.g., from + * Dart_GetType or Dart_GetNullableType. * * \param length The length of the list. * @@ -1966,6 +2112,25 @@ DART_EXPORT Dart_Handle Dart_NewListOf(Dart_CoreType_Id element_type_id, DART_EXPORT Dart_Handle Dart_NewListOfType(Dart_Handle element_type, intptr_t length); +/** + * Returns a List of the desired length with the desired element type, filled + * with the provided object. + * + * \param element_type Handle to a type object. E.g., from Dart_GetType. + * + * \param fill_object Handle to an object of type 'element_type' that will be + * used to populate the list. This parameter can only be Dart_Null() if the + * length of the list is 0 or 'element_type' is a nullable type. + * + * \param length The length of the list. + * + * \return The List object if no error occurs. Otherwise returns + * an error handle. + */ +DART_EXPORT Dart_Handle Dart_NewListOfTypeFilled(Dart_Handle element_type, + Dart_Handle fill_object, + intptr_t length); + /** * Gets the length of a List. * @@ -2495,9 +2660,9 @@ DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj, typedef struct _Dart_NativeArguments* Dart_NativeArguments; /** - * Extracts current isolate data from the native arguments structure. + * Extracts current isolate group data from the native arguments structure. */ -DART_EXPORT void* Dart_GetNativeIsolateData(Dart_NativeArguments args); +DART_EXPORT void* Dart_GetNativeIsolateGroupData(Dart_NativeArguments args); typedef enum { Dart_NativeArgument_kBool = 0, @@ -2800,8 +2965,6 @@ DART_EXPORT Dart_Handle Dart_GetNativeSymbol(Dart_Handle library, typedef enum { Dart_kCanonicalizeUrl = 0, - Dart_kScriptTag, - Dart_kSourceTag, Dart_kImportTag, Dart_kKernelTag, Dart_kImportExtensionTag, @@ -2822,14 +2985,6 @@ typedef enum { * of this tag. The return value should be a string holding the * canonicalized url. * - * Dart_kScriptTag - * - * No longer used. - * - * Dart_kSourceTag - * - * No longer used. - * * Dart_kImportTag * * This tag is used to load a library from IsolateMirror.loadUri. The embedder @@ -2873,6 +3028,59 @@ typedef Dart_Handle (*Dart_LibraryTagHandler)( DART_EXPORT Dart_Handle Dart_SetLibraryTagHandler(Dart_LibraryTagHandler handler); +/** + * Handles deferred loading requests. When this handler is invoked, it should + * eventually load the deferred loading unit with the given id and call + * Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError. It is + * recommended that the loading occur asynchronously, but it is permitted to + * call Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError before the + * handler returns. + * + * If an error is returned, it will be propogated through + * `prefix.loadLibrary()`. This is useful for synchronous + * implementations, which must propogate any unwind errors from + * Dart_DeferredLoadComplete or Dart_DeferredLoadComplete. Otherwise the handler + * should return a non-error such as `Dart_Null()`. + */ +typedef Dart_Handle (*Dart_DeferredLoadHandler)(intptr_t loading_unit_id); + +/** + * Sets the deferred load handler for the current isolate. This handler is + * used to handle loading deferred imports in an AppJIT or AppAOT program. + */ +DART_EXPORT Dart_Handle +Dart_SetDeferredLoadHandler(Dart_DeferredLoadHandler handler); + +/** + * Notifies the VM that a deferred load completed successfully. This function + * will eventually cause the corresponding `prefix.loadLibrary()` futures to + * complete. + * + * Requires the current isolate to be the same current isolate during the + * invocation of the Dart_DeferredLoadHandler. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_DeferredLoadComplete(intptr_t loading_unit_id, + const uint8_t* snapshot_data, + const uint8_t* snapshot_instructions); + +/** + * Notifies the VM that a deferred load failed. This function + * will eventually cause the corresponding `prefix.loadLibrary()` futures to + * complete with an error. + * + * If `transient` is true, future invocations of `prefix.loadLibrary()` will + * trigger new load requests. If false, futures invocation will complete with + * the same error. + * + * Requires the current isolate to be the same current isolate during the + * invocation of the Dart_DeferredLoadHandler. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_DeferredLoadCompleteError(intptr_t loading_unit_id, + const char* error_message, + bool transient); + /** * Canonicalizes a url with respect to some library. * @@ -2899,7 +3107,7 @@ DART_EXPORT Dart_Handle Dart_DefaultCanonicalizeUrl(Dart_Handle base_url, * Requires there to be no current root library. * * \param buffer A buffer which contains a kernel binary (see - * pkg/kernel/binary.md). Must remain valid until isolate shutdown. + * pkg/kernel/binary.md). Must remain valid until isolate group shutdown. * \param buffer_size Length of the passed in buffer. * * \return A handle to the root library, or an error. @@ -2926,7 +3134,8 @@ DART_EXPORT Dart_Handle Dart_RootLibrary(); DART_EXPORT Dart_Handle Dart_SetRootLibrary(Dart_Handle library); /** - * Lookup or instantiate a type by name and type arguments from a Library. + * Lookup or instantiate a legacy type by name and type arguments from a + * Library. * * \param library The library containing the class or interface. * \param class_name The class name for the type. @@ -2943,6 +3152,78 @@ DART_EXPORT Dart_Handle Dart_GetType(Dart_Handle library, intptr_t number_of_type_arguments, Dart_Handle* type_arguments); +/** + * Lookup or instantiate a nullable type by name and type arguments from + * Library. + * + * \param library The library containing the class or interface. + * \param class_name The class name for the type. + * \param number_of_type_arguments Number of type arguments. + * For non parametric types the number of type arguments would be 0. + * \param type_arguments Pointer to an array of type arguments. + * For non parameteric types a NULL would be passed in for this argument. + * + * \return If no error occurs, the type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_GetNullableType(Dart_Handle library, + Dart_Handle class_name, + intptr_t number_of_type_arguments, + Dart_Handle* type_arguments); + +/** + * Lookup or instantiate a non-nullable type by name and type arguments from + * Library. + * + * \param library The library containing the class or interface. + * \param class_name The class name for the type. + * \param number_of_type_arguments Number of type arguments. + * For non parametric types the number of type arguments would be 0. + * \param type_arguments Pointer to an array of type arguments. + * For non parameteric types a NULL would be passed in for this argument. + * + * \return If no error occurs, the type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle +Dart_GetNonNullableType(Dart_Handle library, + Dart_Handle class_name, + intptr_t number_of_type_arguments, + Dart_Handle* type_arguments); + +/** + * Creates a nullable version of the provided type. + * + * \param type The type to be converted to a nullable type. + * + * \return If no error occurs, a nullable type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_TypeToNullableType(Dart_Handle type); + +/** + * Creates a non-nullable version of the provided type. + * + * \param type The type to be converted to a non-nullable type. + * + * \return If no error occurs, a non-nullable type is returned. + * Otherwise an error handle is returned. + */ +DART_EXPORT Dart_Handle Dart_TypeToNonNullableType(Dart_Handle type); + +/** + * A type's nullability. + * + * \param type A Dart type. + * \param result An out parameter containing the result of the check. True if + * the type is of the specified nullability, false otherwise. + * + * \return Returns an error handle if type is not of type Type. + */ +DART_EXPORT Dart_Handle Dart_IsNullableType(Dart_Handle type, bool* result); +DART_EXPORT Dart_Handle Dart_IsNonNullableType(Dart_Handle type, bool* result); +DART_EXPORT Dart_Handle Dart_IsLegacyType(Dart_Handle type, bool* result); + /** * Lookup a class or interface by name from a Library. * @@ -3092,8 +3373,8 @@ typedef enum { typedef struct { Dart_KernelCompilationStatus status; + bool null_safety; char* error; - uint8_t* kernel; intptr_t kernel_size; } Dart_KernelCompilationResult; @@ -3101,6 +3382,27 @@ typedef struct { DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate); DART_EXPORT bool Dart_KernelIsolateIsRunning(); DART_EXPORT Dart_Port Dart_KernelPort(); + +/** + * Compiles the given `script_uri` to a kernel file. + * + * \param platform_kernel A buffer containing the kernel of the platform (e.g. + * `vm_platform_strong.dill`). The VM does not take ownership of this memory. + * + * \param platform_kernel_size The length of the platform_kernel buffer. + * + * \return Returns the result of the compilation. + * + * On a successful compilation the returned [Dart_KernelCompilationResult] has + * a status of [Dart_KernelCompilationStatus_Ok] and the `kernel`/`kernel_size` + * fields are set. The caller takes ownership of the malloc()ed buffer. + * + * On a failed compilation the `error` might be set describing the reason for + * the failed compilation. The caller takes ownership of the malloc()ed + * error. + * + * Requires there to be a current isolate. + */ DART_EXPORT Dart_KernelCompilationResult Dart_CompileToKernel(const char* script_uri, const uint8_t* platform_kernel, @@ -3112,19 +3414,65 @@ typedef struct { const char* uri; const char* source; } Dart_SourceFile; -DART_EXPORT Dart_KernelCompilationResult -Dart_CompileSourcesToKernel(const char* script_uri, - const uint8_t* platform_kernel, - intptr_t platform_kernel_size, - int source_files_count, - Dart_SourceFile source_files[], - bool incremental_compile, - const char* package_config, - const char* multiroot_filepaths, - const char* multiroot_scheme); DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies(); +/** + * Sets the kernel buffer which will be used to load Dart SDK sources + * dynamically at runtime. + * + * \param platform_kernel A buffer containing kernel which has sources for the + * Dart SDK populated. Note: The VM does not take ownership of this memory. + * + * \param platform_kernel_size The length of the platform_kernel buffer. + */ +DART_EXPORT void Dart_SetDartLibrarySourcesKernel( + const uint8_t* platform_kernel, + const intptr_t platform_kernel_size); + +/** + * Detect the null safety opt-in status. + * + * When running from source, it is based on the opt-in status of `script_uri`. + * When running from a kernel buffer, it is based on the mode used when + * generating `kernel_buffer`. + * When running from an appJIT or AOT snapshot, it is based on the mode used + * when generating `snapshot_data`. + * + * \param script_uri Uri of the script that contains the source code + * + * \param package_config Uri of the package configuration file (either in format + * of .packages or .dart_tool/package_config.json) for the null safety + * detection to resolve package imports against. If this parameter is not + * passed the package resolution of the parent isolate should be used. + * + * \param original_working_directory current working directory when the VM + * process was launched, this is used to correctly resolve the path specified + * for package_config. + * + * \param snapshot_data + * + * \param snapshot_instructions Buffers containing a snapshot of the + * isolate or NULL if no snapshot is provided. If provided, the buffers must + * remain valid until the isolate shuts down. + * + * \param kernel_buffer + * + * \param kernel_buffer_size A buffer which contains a kernel/DIL program. Must + * remain valid until isolate shutdown. + * + * \return Returns true if the null safety is opted in by the input being + * run `script_uri`, `snapshot_data` or `kernel_buffer`. + * + */ +DART_EXPORT bool Dart_DetectNullSafety(const char* script_uri, + const char* package_config, + const char* original_working_directory, + const uint8_t* snapshot_data, + const uint8_t* snapshot_instructions, + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size); + #define DART_KERNEL_ISOLATE_NAME "kernel-service" /* @@ -3145,12 +3493,23 @@ DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies(); DART_EXPORT bool Dart_IsServiceIsolate(Dart_Isolate isolate); /** - * Returns the port that script load requests should be sent on. + * Writes the CPU profile to the timeline as a series of 'instant' events. + * + * Note that this is an expensive operation. + * + * \param main_port The main port of the Isolate whose profile samples to write. + * \param error An optional error, must be free()ed by caller. * - * \return Returns the port for load requests or ILLEGAL_PORT if the service - * isolate failed to startup or does not support load requests. + * \return Returns true if the profile is successfully written and false + * otherwise. + */ +DART_EXPORT bool Dart_WriteProfileToTimeline(Dart_Port main_port, char** error); + +/* + * ==================== + * Compilation Feedback + * ==================== */ -DART_EXPORT Dart_Port Dart_ServiceWaitForLoadPort(); /** * Record all functions which have been compiled in the current isolate. @@ -3175,6 +3534,29 @@ Dart_SaveCompilationTrace(uint8_t** buffer, intptr_t* buffer_length); DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_LoadCompilationTrace(uint8_t* buffer, intptr_t buffer_length); +/** + * Record runtime feedback for the current isolate, including type feedback + * and usage counters. + * + * \param buffer Returns a pointer to a buffer containing the trace. + * This buffer is scope allocated and is only valid until the next call to + * Dart_ExitScope. + * \param size Returns the size of the buffer. + * \return Returns an valid handle upon success. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_SaveTypeFeedback(uint8_t** buffer, intptr_t* buffer_length); + +/** + * Compile functions using data from Dart_SaveTypeFeedback. The data must from a + * VM with the same version and compiler flags. + * + * \return Returns an error handle if a compilation error was encountered or a + * version mismatch is detected. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_LoadTypeFeedback(uint8_t* buffer, intptr_t buffer_length); + /* * ============== * Precompilation @@ -3193,62 +3575,127 @@ Dart_LoadCompilationTrace(uint8_t* buffer, intptr_t buffer_length); */ DART_EXPORT Dart_Handle Dart_Precompile(); +typedef void (*Dart_CreateLoadingUnitCallback)( + void* callback_data, + intptr_t loading_unit_id, + void** write_callback_data, + void** write_debug_callback_data); typedef void (*Dart_StreamingWriteCallback)(void* callback_data, const uint8_t* buffer, intptr_t size); +typedef void (*Dart_StreamingCloseCallback)(void* callback_data); + +// On Darwin systems, 'dlsym' adds an '_' to the beginning of the symbol name. +// Use the '...CSymbol' definitions for resolving through 'dlsym'. The actual +// symbol names in the objects are given by the '...AsmSymbol' definitions. +#if defined(__APPLE__) +#define kSnapshotBuildIdCSymbol "kDartSnapshotBuildId" +#define kVmSnapshotDataCSymbol "kDartVmSnapshotData" +#define kVmSnapshotInstructionsCSymbol "kDartVmSnapshotInstructions" +#define kIsolateSnapshotDataCSymbol "kDartIsolateSnapshotData" +#define kIsolateSnapshotInstructionsCSymbol "kDartIsolateSnapshotInstructions" +#else +#define kSnapshotBuildIdCSymbol "_kDartSnapshotBuildId" +#define kVmSnapshotDataCSymbol "_kDartVmSnapshotData" +#define kVmSnapshotInstructionsCSymbol "_kDartVmSnapshotInstructions" +#define kIsolateSnapshotDataCSymbol "_kDartIsolateSnapshotData" +#define kIsolateSnapshotInstructionsCSymbol "_kDartIsolateSnapshotInstructions" +#endif + +#define kSnapshotBuildIdAsmSymbol "_kDartSnapshotBuildId" +#define kVmSnapshotDataAsmSymbol "_kDartVmSnapshotData" +#define kVmSnapshotInstructionsAsmSymbol "_kDartVmSnapshotInstructions" +#define kIsolateSnapshotDataAsmSymbol "_kDartIsolateSnapshotData" +#define kIsolateSnapshotInstructionsAsmSymbol \ + "_kDartIsolateSnapshotInstructions" /** * Creates a precompiled snapshot. * - A root library must have been loaded. * - Dart_Precompile must have been called. * - * Outputs an assembly file defining the symbols - * - kDartVmSnapshotData - * - kDartVmSnapshotInstructions - * - kDartIsolateSnapshotData - * - kDartIsolateSnapshotInstructions + * Outputs an assembly file defining the symbols listed in the definitions + * above. * * The assembly should be compiled as a static or shared library and linked or - * loaded by the embedder. + * loaded by the embedder. Running this snapshot requires a VM compiled with + * DART_PRECOMPILED_SNAPSHOT. The kDartVmSnapshotData and + * kDartVmSnapshotInstructions should be passed to Dart_Initialize. The + * kDartIsolateSnapshotData and kDartIsolateSnapshotInstructions should be + * passed to Dart_CreateIsolateGroup. + * + * The callback will be invoked one or more times to provide the assembly code. + * + * If stripped is true, then the assembly code will not include DWARF + * debugging sections. + * + * If debug_callback_data is provided, debug_callback_data will be used with + * the callback to provide separate debugging information. + * + * \return A valid handle if no error occurs during the operation. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, + void* callback_data, + bool stripped, + void* debug_callback_data); +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsAssemblies( + Dart_CreateLoadingUnitCallback next_callback, + void* next_callback_data, + bool stripped, + Dart_StreamingWriteCallback write_callback, + Dart_StreamingCloseCallback close_callback); + +/** + * Creates a precompiled snapshot. + * - A root library must have been loaded. + * - Dart_Precompile must have been called. + * + * Outputs an ELF shared library defining the symbols + * - _kDartVmSnapshotData + * - _kDartVmSnapshotInstructions + * - _kDartIsolateSnapshotData + * - _kDartIsolateSnapshotInstructions + * + * The shared library should be dynamically loaded by the embedder. * Running this snapshot requires a VM compiled with DART_PRECOMPILED_SNAPSHOT. * The kDartVmSnapshotData and kDartVmSnapshotInstructions should be passed to * Dart_Initialize. The kDartIsolateSnapshotData and - * kDartIsoalteSnapshotInstructions should be passed to Dart_CreateIsolate. + * kDartIsolateSnapshotInstructions should be passed to Dart_CreateIsolate. * - * The callback will be invoked one or more times to provide the assembly code. + * The callback will be invoked one or more times to provide the binary output. + * + * If stripped is true, then the binary output will not include DWARF + * debugging sections. + * + * If debug_callback_data is provided, debug_callback_data will be used with + * the callback to provide separate debugging information. * * \return A valid handle if no error occurs during the operation. */ DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle -Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, - void* callback_data); +Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback, + void* callback_data, + bool stripped, + void* debug_callback_data); +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsElfs(Dart_CreateLoadingUnitCallback next_callback, + void* next_callback_data, + bool stripped, + Dart_StreamingWriteCallback write_callback, + Dart_StreamingCloseCallback close_callback); /** * Like Dart_CreateAppAOTSnapshotAsAssembly, but only includes - * kDartVmSnapshotData and kDartVmSnapshotInstructions. + * kDartVmSnapshotData and kDartVmSnapshotInstructions. It also does + * not strip DWARF information from the generated assembly or allow for + * separate debug information. */ DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_CreateVMAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, void* callback_data); -/** - * Same as Dart_CreateAppAOTSnapshotAsAssembly, except all the pieces are - * provided directly as bytes that the embedder can load with mmap. The - * instructions pieces must be loaded with read and execute permissions; the - * other pieces may be loaded as read-only. - */ -DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle -Dart_CreateAppAOTSnapshotAsBlobs(uint8_t** vm_snapshot_data_buffer, - intptr_t* vm_snapshot_data_size, - uint8_t** vm_snapshot_instructions_buffer, - intptr_t* vm_snapshot_instructions_size, - uint8_t** isolate_snapshot_data_buffer, - intptr_t* isolate_snapshot_data_size, - uint8_t** isolate_snapshot_instructions_buffer, - intptr_t* isolate_snapshot_instructions_size, - const uint8_t* shared_data, - const uint8_t* shared_instructions); - /** * Sorts the class-ids in depth first traversal order of the inheritance * tree. This is a costly operation, but it can make method dispatch @@ -3263,13 +3710,12 @@ DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_SortClasses(); * startup and quicker warmup in a subsequent process. * * Outputs a snapshot in two pieces. The pieces should be passed to - * Dart_CreateIsolate in a VM using the same VM snapshot pieces used in the + * Dart_CreateIsolateGroup in a VM using the same VM snapshot pieces used in the * current VM. The instructions piece must be loaded with read and execute * permissions; the data piece may be loaded as read-only. * - * - Requires the VM to have been started with --load-deferred-eagerly. * - Requires the VM to have not been started with --precompilation. - * - Not supported when targeting IA32 or DBC. + * - Not supported when targeting IA32. * - The VM writing the snapshot and the VM reading the snapshot must be the * same version, must be built in the same DEBUG/RELEASE/PRODUCT mode, must * be targeting the same architecture, and must both be in checked mode or @@ -3284,8 +3730,7 @@ DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_CreateAppJITSnapshotAsBlobs(uint8_t** isolate_snapshot_data_buffer, intptr_t* isolate_snapshot_data_size, uint8_t** isolate_snapshot_instructions_buffer, - intptr_t* isolate_snapshot_instructions_size, - const uint8_t* reused_instructions); + intptr_t* isolate_snapshot_instructions_size); /** * Like Dart_CreateAppJITSnapshotAsBlobs, but also creates a new VM snapshot. @@ -3329,4 +3774,10 @@ DART_EXPORT bool Dart_IsPrecompiledRuntime(); */ DART_EXPORT void Dart_DumpNativeStackTrace(void* context); +/** + * Indicate that the process is about to abort, and the Dart VM should not + * attempt to cleanup resources. + */ +DART_EXPORT void Dart_PrepareToAbort(); + #endif /* INCLUDE_DART_API_H_ */ /* NOLINT */ diff --git a/dart/include/dart_embedder_api.h b/dart/include/dart_embedder_api.h index eda9059..e565ebf 100644 --- a/dart/include/dart_embedder_api.h +++ b/dart/include/dart_embedder_api.h @@ -5,17 +5,27 @@ #ifndef RUNTIME_INCLUDE_DART_EMBEDDER_API_H_ #define RUNTIME_INCLUDE_DART_EMBEDDER_API_H_ -#include "dart_api.h" -#include "dart_tools_api.h" +#include "include/dart_api.h" +#include "include/dart_tools_api.h" namespace dart { namespace embedder { // Initialize all subsystems of the embedder. +// +// Must be called before the `Dart_Initialize()` call to initialize the +// Dart VM. +// // Returns true on success and false otherwise, in which case error would // contain error message. DART_WARN_UNUSED_RESULT bool InitOnce(char** error); +// Cleans up all subsystems of the embedder. +// +// Must be called after the `Dart_Cleanup()` call to initialize the +// Dart VM. +void Cleanup(); + // Common arguments that are passed to isolate creation callback and to // API methods that create isolates. struct IsolateCreationData { @@ -29,8 +39,11 @@ struct IsolateCreationData { // Isolate creation flags. Might be absent. Dart_IsolateFlags* flags; + // Isolate group callback data. + void* isolate_group_data; + // Isolate callback data. - void* callback_data; + void* isolate_data; }; // Create and initialize kernel-service isolate. This method should be used @@ -57,23 +70,38 @@ struct VmServiceConfiguration { // Default port. See enum above for special values. int port; + // If non-null, connection information for the VM service will be output to a + // file in JSON format at the location specified. + const char* write_service_info_filename; + // TODO(vegorov) document these ones. bool dev_mode; bool deterministic; + bool disable_auth_codes; }; -// Create and initialize vm-service isolate. This method should be used -// when VM invokes isolate creation callback with DART_VM_SERVICE_ISOLATE_NAME -// as script_uri. -// The isolate is created from the given kernel binary that is expected to -// contain all necessary vmservice libraries. +// Create and initialize vm-service isolate from the given AOT snapshot, which +// is expected to contain all necessary 'vm-service' libraries. +// This method should be used when VM invokes isolate creation callback with +// DART_VM_SERVICE_ISOLATE_NAME as script_uri. DART_WARN_UNUSED_RESULT Dart_Isolate CreateVmServiceIsolate(const IsolateCreationData& data, const VmServiceConfiguration& config, - const uint8_t* kernel_buffer, - intptr_t kernel_buffer_size, + const uint8_t* isolate_data, + const uint8_t* isolate_instr, char** error); +// Create and initialize vm-service isolate from the given kernel binary, which +// is expected to contain all necessary 'vm-service' libraries. +// This method should be used when VM invokes isolate creation callback with +// DART_VM_SERVICE_ISOLATE_NAME as script_uri. +DART_WARN_UNUSED_RESULT Dart_Isolate +CreateVmServiceIsolateFromKernel(const IsolateCreationData& data, + const VmServiceConfiguration& config, + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size, + char** error); + } // namespace embedder } // namespace dart diff --git a/dart/include/dart_mirrors_api.h b/dart/include/dart_mirrors_api.h deleted file mode 100644 index 6352f92..0000000 --- a/dart/include/dart_mirrors_api.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file - * for details. All rights reserved. Use of this source code is governed by a - * BSD-style license that can be found in the LICENSE file. - */ - -#ifndef RUNTIME_INCLUDE_DART_MIRRORS_API_H_ -#define RUNTIME_INCLUDE_DART_MIRRORS_API_H_ - -#include "dart_api.h" - -/** - * Returns the simple name for the provided type. - */ -DART_EXPORT Dart_Handle Dart_TypeName(Dart_Handle type); - -/** - * Returns the qualified name for the provided type. - */ -DART_EXPORT Dart_Handle Dart_QualifiedTypeName(Dart_Handle type); - -/** - * Returns a list of the names of all functions or methods declared in - * a library or class. - * - * \param target A library or class. - * - * \return If no error occurs, a list of strings is returned. - * Otherwise an error handle is returned. - */ -DART_EXPORT Dart_Handle Dart_GetFunctionNames(Dart_Handle target); - -/** - * Looks up a function or method declaration by name from a library or - * class. - * - * \param target The library or class containing the function. - * \param function_name The name of the function. - * - * \return If an error is encountered, returns an error handle. - * Otherwise returns a function handle if the function is found of - * Dart_Null() if the function is not found. - */ -DART_EXPORT Dart_Handle Dart_LookupFunction(Dart_Handle target, - Dart_Handle function_name); - -/** - * Returns the name for the provided function or method. - * - * \return A valid string handle if no error occurs during the - * operation. - */ -DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function); - -/** - * Returns a handle to the owner of a function. - * - * The owner of an instance method or a static method is its defining - * class. The owner of a top-level function is its defining - * library. The owner of the function of a non-implicit closure is the - * function of the method or closure that defines the non-implicit - * closure. - * - * \return A valid handle to the owner of the function, or an error - * handle if the argument is not a valid handle to a function. - */ -DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function); - -/** - * Determines whether a function handle referes to a static function - * of method. - * - * For the purposes of the embedding API, a top-level function is - * implicitly declared static. - * - * \param function A handle to a function or method declaration. - * \param is_static Returns whether the function or method is declared static. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function, - bool* is_static); - -/** - * Determines whether a function handle referes to a constructor. - * - * \param function A handle to a function or method declaration. - * \param is_static Returns whether the function or method is a constructor. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_FunctionIsConstructor(Dart_Handle function, - bool* is_constructor); -/* TODO(turnidge): Document behavior for factory constructors too. */ - -/** - * Determines whether a function or method is a getter. - * - * \param function A handle to a function or method declaration. - * \param is_static Returns whether the function or method is a getter. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_FunctionIsGetter(Dart_Handle function, - bool* is_getter); - -/** - * Determines whether a function or method is a setter. - * - * \param function A handle to a function or method declaration. - * \param is_static Returns whether the function or method is a setter. - * - * \return A valid handle if no error occurs during the operation. - */ -DART_EXPORT Dart_Handle Dart_FunctionIsSetter(Dart_Handle function, - bool* is_setter); - -/** - * Returns the name of a library as declared in the #library directive. - */ -DART_EXPORT Dart_Handle Dart_LibraryName(Dart_Handle library); - -/** - * Returns a list of the names of all classes and interfaces declared - * in a library. - * - * \return If no error occurs, a list of strings is returned. - * Otherwise an error handle is returned. - */ -DART_EXPORT Dart_Handle Dart_LibraryGetClassNames(Dart_Handle library); - -/** - * Retrieves the function of a closure. - * - * \return A handle to the function of the closure, or an error handle if the - * argument is not a closure. - */ -DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure); - -#endif /* INCLUDE_DART_MIRRORS_API_H_ */ /* NOLINT */ diff --git a/dart/include/dart_native_api.h b/dart/include/dart_native_api.h index ae31e47..495d454 100644 --- a/dart/include/dart_native_api.h +++ b/dart/include/dart_native_api.h @@ -83,16 +83,26 @@ typedef struct _Dart_CObject { } as_external_typed_data; } value; } Dart_CObject; +// This struct is versioned by DART_API_DL_MAJOR_VERSION, bump the version when +// changing this struct. /** - * Posts a message on some port. The message will contain the - * Dart_CObject object graph rooted in 'message'. + * Posts a message on some port. The message will contain the Dart_CObject + * object graph rooted in 'message'. * - * While the message is being sent the state of the graph of - * Dart_CObject structures rooted in 'message' should not be accessed, - * as the message generation will make temporary modifications to the - * data. When the message has been sent the graph will be fully - * restored. + * While the message is being sent the state of the graph of Dart_CObject + * structures rooted in 'message' should not be accessed, as the message + * generation will make temporary modifications to the data. When the message + * has been sent the graph will be fully restored. + * + * If true is returned, the message was enqueued, and finalizers for external + * typed data will eventually run, even if the receiving isolate shuts down + * before processing the message. If false is returned, the message was not + * enqueued and ownership of external typed data in the message remains with the + * caller. + * + * This function may be called on any thread when the VM is running (that is, + * after Dart_Initialize has returned and before Dart_Cleanup has been called). * * \param port_id The destination port. * \param message The message to send. @@ -122,7 +132,6 @@ DART_EXPORT bool Dart_PostInteger(Dart_Port port_id, int64_t message); * data references from the message are allocated by the caller and * will be reclaimed when returning to it. */ - typedef void (*Dart_NativeMessageHandler)(Dart_Port dest_port_id, Dart_CObject* message); @@ -171,4 +180,15 @@ DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_CompileAll(); DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_ReadAllBytecode(); +/** + * Finalizes all classes. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_FinalizeAllClasses(); + +/* This function is intentionally undocumented. + * + * It should not be used outside internal tests. + */ +DART_EXPORT void* Dart_ExecuteInternalCommand(const char* command, void* arg); + #endif /* INCLUDE_DART_NATIVE_API_H_ */ /* NOLINT */ diff --git a/dart/include/dart_tools_api.h b/dart/include/dart_tools_api.h index 49b1f19..4c86a82 100644 --- a/dart/include/dart_tools_api.h +++ b/dart/include/dart_tools_api.h @@ -301,7 +301,8 @@ DART_EXPORT bool Dart_IsReloading(); /** * Returns a timestamp in microseconds. This timestamp is suitable for - * passing into the timeline system. + * passing into the timeline system, and uses the same monotonic clock + * as dart:developer's Timeline.now. * * \return A timestamp that can be passed to the timeline system. */ @@ -343,58 +344,6 @@ DART_EXPORT int64_t Dart_TimelineGetMicros(); */ DART_EXPORT void Dart_GlobalTimelineSetRecordedStreams(int64_t stream_mask); -typedef enum { - /** Indicates a new stream is being output */ - Dart_StreamConsumer_kStart = 0, - /** Data for the current stream */ - Dart_StreamConsumer_kData = 1, - /** Indicates stream is finished */ - Dart_StreamConsumer_kFinish = 2, -} Dart_StreamConsumer_State; - -/** - * A stream consumer callback function. - * - * This function will be called repeatedly until there is no more data in a - * stream and there are no more streams. - * - * \param state Indicates a new stream, data, or a finished stream. - * \param stream_name A name for this stream. Not guaranteed to be meaningful. - * \param buffer A pointer to the stream data. - * \param buffer_length The number of bytes at buffer that should be consumed. - * \param stream_callback_data The pointer passed in when requesting the stream. - * - * At the start of each stream state will be DART_STREAM_CONSUMER_STATE_START - * and buffer will be NULL. - * - * For each chunk of data the state will be DART_STREAM_CONSUMER_STATE_DATA - * and buffer will not be NULL. - * - * At the end of each stream state will be DART_STREAM_CONSUMER_STATE_FINISH - * and buffer will be NULL. - */ -typedef void (*Dart_StreamConsumer)(Dart_StreamConsumer_State state, - const char* stream_name, - const uint8_t* buffer, - intptr_t buffer_length, - void* stream_callback_data); - -/** - * Get the timeline for entire VM (including all isolates). - * - * NOTE: The timeline retrieved from this API call may not include the most - * recent events. - * - * \param consumer A Dart_StreamConsumer. - * \param user_data User data passed into consumer. - * - * NOTE: The trace-event format is documented here: https://goo.gl/hDZw5M - * - * \return True if a stream was output. - */ -DART_EXPORT bool Dart_GlobalTimelineGetTrace(Dart_StreamConsumer consumer, - void* user_data); - typedef enum { Dart_Timeline_Event_Begin, // Phase = 'B'. Dart_Timeline_Event_End, // Phase = 'E'. @@ -412,13 +361,17 @@ typedef enum { /** * Add a timeline event to the embedder stream. * - * \param label The name of the evnet. + * \param label The name of the event. Its lifetime must extend at least until + * Dart_Cleanup. * \param timestamp0 The first timestamp of the event. * \param timestamp1_or_async_id The second timestamp of the event or * the async id. * \param argument_count The number of argument names and values. - * \param argument_names An array of names of the arguments. - * \param argument_values An array of values of the arguments. + * \param argument_names An array of names of the arguments. The lifetime of the + * names must extend at least until Dart_Cleanup. The array may be reclaimed + * when this call returns. + * \param argument_values An array of values of the arguments. The values and + * the array may be reclaimed when this call returns. */ DART_EXPORT void Dart_TimelineEvent(const char* label, int64_t timestamp0, @@ -436,31 +389,6 @@ DART_EXPORT void Dart_TimelineEvent(const char* label, */ DART_EXPORT void Dart_SetThreadName(const char* name); -/** - * Called by the VM to let the embedder know when to start recording into the - * timeline. Can be called from any thread. - */ -typedef void (*Dart_EmbedderTimelineStartRecording)(); - -/** - * Called by the VM to let the embedder know when to stop recording into the - * timeline. Can be called from any thread. - */ -typedef void (*Dart_EmbedderTimelineStopRecording)(); - -/** - * Sets the embedder timeline callbacks. These callbacks are used by the VM - * to notify the embedder of timeline recording state changes. - * - * \param start_recording See Dart_EmbedderTimelineStartRecording. - * \param stop_recording See Dart_EmbedderTimelineStopRecording. - * - * NOTE: To avoid races, this should be called before Dart_Initialize. - */ -DART_EXPORT void Dart_SetEmbedderTimelineCallbacks( - Dart_EmbedderTimelineStartRecording start_recording, - Dart_EmbedderTimelineStopRecording stop_recording); - /* * ======= * Metrics @@ -470,8 +398,8 @@ DART_EXPORT void Dart_SetEmbedderTimelineCallbacks( /** * Return metrics gathered for the VM and individual isolates. * - * NOTE: Metrics are not available in PRODUCT builds of Dart. - * Calling the metric functions on a PRODUCT build might return invalid metrics. + * NOTE: Non-heap metrics are not available in PRODUCT builds of Dart. + * Calling the non-heap metric functions on a PRODUCT build might return invalid metrics. */ DART_EXPORT int64_t Dart_VMIsolateCountMetric(); // Counter DART_EXPORT int64_t Dart_VMCurrentRSSMetric(); // Byte