Version 2.13.0-49.0.dev
Merge commit '9f68048cae8ec3344e845917f3f42dbc8340e8a3' into 'dev'
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 7e0dc6a..0fcaf18 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -153,7 +153,7 @@
}
abstract class Compiler {
- final int isolateId;
+ final int isolateGroupId;
final FileSystem fileSystem;
final Uri platformKernelPath;
final bool enableAsserts;
@@ -172,7 +172,7 @@
CompilerOptions options;
- Compiler(this.isolateId, this.fileSystem, this.platformKernelPath,
+ Compiler(this.isolateGroupId, this.fileSystem, this.platformKernelPath,
{this.enableAsserts: false,
this.nullSafety: kNullSafetyOptionUnspecified,
this.experimentalFlags: null,
@@ -214,7 +214,7 @@
if (errors.isEmpty) {
// Record dependencies only if compilation was error free.
- _recordDependencies(isolateId, component, options.packagesFileUri);
+ _recordDependencies(isolateGroupId, component, options.packagesFileUri);
}
return compilerResult;
@@ -289,14 +289,14 @@
IncrementalCompiler generator;
IncrementalCompilerWrapper(
- int isolateId, FileSystem fileSystem, Uri platformKernelPath,
+ int isolateGroupId, FileSystem fileSystem, Uri platformKernelPath,
{bool enableAsserts: false,
int nullSafety: kNullSafetyOptionUnspecified,
List<String> experimentalFlags: null,
String packageConfig: null,
String invocationModes: '',
String verbosityLevel: Verbosity.defaultValue})
- : super(isolateId, fileSystem, platformKernelPath,
+ : super(isolateGroupId, fileSystem, platformKernelPath,
enableAsserts: enableAsserts,
nullSafety: nullSafety,
experimentalFlags: experimentalFlags,
@@ -308,7 +308,7 @@
factory IncrementalCompilerWrapper.forExpressionCompilationOnly(
Component component,
- int isolateId,
+ int isolateGroupId,
FileSystem fileSystem,
Uri platformKernelPath,
{bool enableAsserts: false,
@@ -316,7 +316,7 @@
String packageConfig: null,
String invocationModes: ''}) {
IncrementalCompilerWrapper result = IncrementalCompilerWrapper(
- isolateId, fileSystem, platformKernelPath,
+ isolateGroupId, fileSystem, platformKernelPath,
enableAsserts: enableAsserts,
experimentalFlags: experimentalFlags,
packageConfig: packageConfig,
@@ -342,9 +342,9 @@
void accept() => generator.accept();
void invalidate(Uri uri) => generator.invalidate(uri);
- Future<IncrementalCompilerWrapper> clone(int isolateId) async {
+ Future<IncrementalCompilerWrapper> clone(int isolateGroupId) async {
IncrementalCompilerWrapper clone = IncrementalCompilerWrapper(
- isolateId, fileSystem, platformKernelPath,
+ isolateGroupId, fileSystem, platformKernelPath,
enableAsserts: enableAsserts,
nullSafety: nullSafety,
experimentalFlags: experimentalFlags,
@@ -359,7 +359,7 @@
// clone should be used for.
MemoryFileSystem memoryFileSystem = (fileSystem as HybridFileSystem).memory;
- String filename = 'full-component-$isolateId.dill';
+ String filename = 'full-component-$isolateGroupId.dill';
Sink sink = FileSink(memoryFileSystem.entityForUri(Uri.file(filename)));
new BinaryPrinter(sink).writeComponentFile(fullComponent);
await sink.close();
@@ -374,7 +374,7 @@
final bool requireMain;
SingleShotCompilerWrapper(
- int isolateId, FileSystem fileSystem, Uri platformKernelPath,
+ int isolateGroupId, FileSystem fileSystem, Uri platformKernelPath,
{this.requireMain: false,
bool enableAsserts: false,
int nullSafety: kNullSafetyOptionUnspecified,
@@ -382,7 +382,7 @@
String packageConfig: null,
String invocationModes: '',
String verbosityLevel: Verbosity.defaultValue})
- : super(isolateId, fileSystem, platformKernelPath,
+ : super(isolateGroupId, fileSystem, platformKernelPath,
enableAsserts: enableAsserts,
nullSafety: nullSafety,
experimentalFlags: experimentalFlags,
@@ -405,18 +405,15 @@
}
}
-// TODO(33428): This state is leaked on isolate shutdown.
-final Map<int, IncrementalCompilerWrapper> isolateCompilers =
- new Map<int, IncrementalCompilerWrapper>();
-final Map<int, List<Uri>> isolateDependencies = new Map<int, List<Uri>>();
-final Map<int, _ExpressionCompilationFromDillSettings> isolateLoadNotifies =
- new Map<int, _ExpressionCompilationFromDillSettings>();
+final Map<int, IncrementalCompilerWrapper> isolateCompilers = {};
+final Map<int, List<Uri>> isolateDependencies = {};
+final Map<int, _ExpressionCompilationFromDillSettings> isolateLoadNotifies = {};
-IncrementalCompilerWrapper lookupIncrementalCompiler(int isolateId) {
- return isolateCompilers[isolateId];
+IncrementalCompilerWrapper lookupIncrementalCompiler(int isolateGroupId) {
+ return isolateCompilers[isolateGroupId];
}
-Future<Compiler> lookupOrBuildNewIncrementalCompiler(int isolateId,
+Future<Compiler> lookupOrBuildNewIncrementalCompiler(int isolateGroupId,
List sourceFiles, Uri platformKernelPath, List<int> platformKernel,
{bool enableAsserts: false,
int nullSafety: kNullSafetyOptionUnspecified,
@@ -426,7 +423,8 @@
String multirootScheme,
String invocationModes: '',
String verbosityLevel: Verbosity.defaultValue}) async {
- IncrementalCompilerWrapper compiler = lookupIncrementalCompiler(isolateId);
+ IncrementalCompilerWrapper compiler =
+ lookupIncrementalCompiler(isolateGroupId);
if (compiler != null) {
updateSources(compiler, sourceFiles);
invalidateSources(compiler, sourceFiles);
@@ -439,7 +437,7 @@
sourceFiles[1] == null) {
// Just use first compiler that should represent main isolate as a source for cloning.
var source = isolateCompilers.entries.first;
- compiler = await source.value.clone(isolateId);
+ compiler = await source.value.clone(isolateGroupId);
} else {
FileSystem fileSystem = _buildFileSystem(
sourceFiles, platformKernel, multirootFilepaths, multirootScheme);
@@ -449,7 +447,7 @@
// isolate needs to receive a message indicating that particular
// isolate was shut down. Message should be handled here in this script.
compiler = new IncrementalCompilerWrapper(
- isolateId, fileSystem, platformKernelPath,
+ isolateGroupId, fileSystem, platformKernelPath,
enableAsserts: enableAsserts,
nullSafety: nullSafety,
experimentalFlags: experimentalFlags,
@@ -457,7 +455,7 @@
invocationModes: invocationModes,
verbosityLevel: verbosityLevel);
}
- isolateCompilers[isolateId] = compiler;
+ isolateCompilers[isolateGroupId] = compiler;
}
return compiler;
}
@@ -494,7 +492,7 @@
// kernel_isolate.cc and Loader::SendKernelRequest in loader.cc.
Future _processExpressionCompilationRequest(request) async {
final SendPort port = request[1];
- final int isolateId = request[2];
+ final int isolateGroupId = request[2];
final dynamic dart_platform_kernel = request[3];
final String expression = request[4];
final List<String> definitions = request[5].cast<String>();
@@ -508,15 +506,15 @@
final List<String> experimentalFlags =
request[13] != null ? request[13].cast<String>() : null;
- IncrementalCompilerWrapper compiler = isolateCompilers[isolateId];
+ IncrementalCompilerWrapper compiler = isolateCompilers[isolateGroupId];
_ExpressionCompilationFromDillSettings isolateLoadDillData =
- isolateLoadNotifies[isolateId];
+ isolateLoadNotifies[isolateGroupId];
if (isolateLoadDillData != null) {
// Check if we can reuse the compiler.
if (isolateLoadDillData.blobLoadCount != blobLoadCount ||
isolateLoadDillData.prevDillCount != dillData.length) {
- compiler = isolateCompilers[isolateId] = null;
+ compiler = isolateCompilers[isolateGroupId] = null;
}
}
@@ -525,7 +523,7 @@
if (verbose) {
print("DFE: Initializing compiler from ${dillData.length} dill files");
}
- isolateLoadNotifies[isolateId] =
+ isolateLoadNotifies[isolateGroupId] =
new _ExpressionCompilationFromDillSettings(
blobLoadCount, dillData.length);
@@ -585,11 +583,11 @@
// isolate was shut down. Message should be handled here in this script.
try {
compiler = new IncrementalCompilerWrapper.forExpressionCompilationOnly(
- component, isolateId, fileSystem, null,
+ component, isolateGroupId, fileSystem, null,
enableAsserts: enableAsserts,
experimentalFlags: experimentalFlags,
packageConfig: dotPackagesFile);
- isolateCompilers[isolateId] = compiler;
+ isolateCompilers[isolateGroupId] = compiler;
await compiler.compile(
component.mainMethod?.enclosingLibrary?.importUri ??
component.libraries.last.importUri);
@@ -640,8 +638,8 @@
}
void _recordDependencies(
- int isolateId, Component component, Uri packageConfig) {
- final dependencies = isolateDependencies[isolateId] ??= <Uri>[];
+ int isolateGroupId, Component component, Uri packageConfig) {
+ final dependencies = isolateDependencies[isolateGroupId] ??= <Uri>[];
if (component != null) {
for (var lib in component.libraries) {
@@ -673,8 +671,9 @@
return utf8.encode(uris.map(_escapeDependency).join(" "));
}
-Future _processListDependenciesRequest(SendPort port, int isolateId) async {
- final List<Uri> dependencies = isolateDependencies[isolateId] ?? <Uri>[];
+Future _processListDependenciesRequest(
+ SendPort port, int isolateGroupId) async {
+ final List<Uri> dependencies = isolateDependencies[isolateGroupId] ?? <Uri>[];
CompilationResult result;
try {
@@ -687,10 +686,10 @@
}
Future _processIsolateShutdownNotification(request) async {
- final int isolateId = request[1];
- isolateCompilers.remove(isolateId);
- isolateDependencies.remove(isolateId);
- isolateLoadNotifies.remove(isolateId);
+ final int isolateGroupId = request[1];
+ isolateCompilers.remove(isolateGroupId);
+ isolateDependencies.remove(isolateGroupId);
+ isolateLoadNotifies.remove(isolateGroupId);
}
Future _processLoadRequest(request) async {
@@ -733,10 +732,10 @@
}
final SendPort port = request[1];
- final int isolateId = request[7];
+ final int isolateGroupId = request[7];
if (tag == kListDependenciesTag) {
- await _processListDependenciesRequest(port, isolateId);
+ await _processListDependenciesRequest(port, isolateGroupId);
return;
}
@@ -777,7 +776,7 @@
if (tag == kUpdateSourcesTag) {
assert(incremental,
"Incremental compiler required for use of 'kUpdateSourcesTag'");
- compiler = lookupIncrementalCompiler(isolateId);
+ compiler = lookupIncrementalCompiler(isolateGroupId);
if (compiler == null) {
port.send(new CompilationResult.errors(
["No incremental compiler available for this isolate."], null)
@@ -790,7 +789,7 @@
} else if (tag == kAcceptTag) {
assert(
incremental, "Incremental compiler required for use of 'kAcceptTag'");
- compiler = lookupIncrementalCompiler(isolateId);
+ compiler = lookupIncrementalCompiler(isolateGroupId);
// There are unit tests that invoke the IncrementalCompiler directly and
// request a reload, meaning that we won't have a compiler for this isolate.
if (compiler != null) {
@@ -841,7 +840,7 @@
// watch the performance though.
if (incremental) {
compiler = await lookupOrBuildNewIncrementalCompiler(
- isolateId, sourceFiles, platformKernelPath, platformKernel,
+ isolateGroupId, sourceFiles, platformKernelPath, platformKernel,
enableAsserts: enableAsserts,
nullSafety: nullSafety,
experimentalFlags: experimentalFlags,
@@ -854,7 +853,7 @@
FileSystem fileSystem = _buildFileSystem(
sourceFiles, platformKernel, multirootFilepaths, multirootScheme);
compiler = new SingleShotCompilerWrapper(
- isolateId, fileSystem, platformKernelPath,
+ isolateGroupId, fileSystem, platformKernelPath,
requireMain: false,
enableAsserts: enableAsserts,
nullSafety: nullSafety,
@@ -1007,7 +1006,7 @@
false /* incremental */,
false /* snapshot */,
kNullSafetyOptionUnspecified /* null safety */,
- 1 /* isolateId chosen randomly */,
+ 1 /* isolateGroupId chosen randomly */,
[] /* source files */,
false /* enable asserts */,
null /* experimental_flags */,
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index d2de37c..a532bb4 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -886,10 +886,10 @@
char** error) {
const char* result = NULL;
Zone* zone = thread->zone();
- Isolate* isolate = thread->isolate();
- if (isolate->HasTagHandler()) {
+ auto isolate_group = thread->isolate_group();
+ if (isolate_group->HasTagHandler()) {
const Object& obj = Object::Handle(
- isolate->CallTagHandler(Dart_kCanonicalizeUrl, library, uri));
+ isolate_group->CallTagHandler(Dart_kCanonicalizeUrl, library, uri));
if (obj.IsString()) {
result = String2UTF8(String::Cast(obj));
} else if (obj.IsError()) {
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index a245378..2cc879a 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -662,7 +662,7 @@
DEFINE_NATIVE_ENTRY(IsolateMirror_loadUri, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(String, uri, arguments->NativeArgAt(0));
- if (!isolate->HasTagHandler()) {
+ if (!isolate->group()->HasTagHandler()) {
ThrowLanguageError("no library handler registered");
}
@@ -675,7 +675,7 @@
} else {
isolate->BlockClassFinalization();
const Object& result = Object::Handle(
- zone, isolate->CallTagHandler(
+ zone, isolate->group()->CallTagHandler(
Dart_kCanonicalizeUrl,
Library::Handle(
zone, isolate->group()->object_store()->root_library()),
@@ -703,7 +703,7 @@
// Request the embedder to load the library.
isolate->BlockClassFinalization();
Object& result = Object::Handle(
- zone, isolate->CallTagHandler(
+ zone, isolate->group()->CallTagHandler(
Dart_kImportTag,
Library::Handle(
zone, isolate->group()->object_store()->root_library()),
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index 93534de..49c4036 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -74,7 +74,7 @@
if (is_fuchsia) {
if (using_fuchsia_gn_sdk) {
extra_deps = [
- "$fuchsia_sdk_root/fidl/fuchsia.deprecatedtimezone",
+ "$fuchsia_sdk_root/fidl/fuchsia.intl",
"$fuchsia_sdk_root/pkg/async",
"$fuchsia_sdk_root/pkg/async-default",
"$fuchsia_sdk_root/pkg/async-loop",
@@ -87,7 +87,7 @@
]
} else if (using_fuchsia_sdk) {
extra_deps = [
- "$fuchsia_sdk_root/fidl:fuchsia.deprecatedtimezone",
+ "$fuchsia_sdk_root/fidl:fuchsia.intl",
"$fuchsia_sdk_root/pkg:async-loop",
"$fuchsia_sdk_root/pkg:async-loop-default",
"$fuchsia_sdk_root/pkg:inspect",
@@ -98,9 +98,7 @@
]
} else {
extra_deps = [
- # TODO(US-399): Remove time_service specific code when it is no longer
- # necessary.
- "//sdk/fidl/fuchsia.deprecatedtimezone",
+ "//sdk/fidl/fuchsia.intl",
"//sdk/lib/sys/cpp",
"//sdk/lib/sys/inspect/cpp",
"//zircon/public/lib/fbl",
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 97dab6c..f371e1b 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1895,9 +1895,9 @@
return mutator_thread_;
}
-ObjectPtr Isolate::CallTagHandler(Dart_LibraryTag tag,
- const Object& arg1,
- const Object& arg2) {
+ObjectPtr IsolateGroup::CallTagHandler(Dart_LibraryTag tag,
+ const Object& arg1,
+ const Object& arg2) {
Thread* thread = Thread::Current();
Api::Scope api_scope(thread);
Dart_Handle api_arg1 = Api::NewHandle(thread, arg1.ptr());
@@ -1906,7 +1906,7 @@
{
TransitionVMToNative transition(thread);
ASSERT(HasTagHandler());
- api_result = group()->library_tag_handler()(tag, api_arg1, api_arg2);
+ api_result = library_tag_handler()(tag, api_arg1, api_arg2);
}
return Api::UnwrapHandle(api_result);
}
@@ -2473,7 +2473,6 @@
StackZone zone(thread);
HandleScope handle_scope(thread);
ServiceIsolate::SendIsolateShutdownMessage();
- KernelIsolate::NotifyAboutIsolateShutdown(this);
#if !defined(PRODUCT)
debugger()->Shutdown();
#endif
@@ -2545,6 +2544,8 @@
const bool shutdown_group =
isolate_group->UnregisterIsolateDecrementCount(isolate);
if (shutdown_group) {
+ KernelIsolate::NotifyAboutIsolateGroupShutdown(isolate_group);
+
#if !defined(DART_PRECOMPILED_RUNTIME)
if (!is_vm_isolate) {
Thread::EnterIsolateGroupAsHelper(isolate_group, Thread::kUnknownTask,
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index aa8575f..96f6908 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -600,6 +600,10 @@
void IncreaseMutatorCount(Isolate* mutator);
void DecreaseMutatorCount(Isolate* mutator);
+ bool HasTagHandler() const { return library_tag_handler() != nullptr; }
+ ObjectPtr CallTagHandler(Dart_LibraryTag tag,
+ const Object& arg1,
+ const Object& arg2);
Dart_LibraryTagHandler library_tag_handler() const {
return library_tag_handler_;
}
@@ -724,7 +728,7 @@
#endif
}
- uint64_t id() { return id_; }
+ uint64_t id() const { return id_; }
static void Init();
static void Cleanup();
@@ -1102,12 +1106,6 @@
environment_callback_ = value;
}
- bool HasTagHandler() const {
- return group()->library_tag_handler() != nullptr;
- }
- ObjectPtr CallTagHandler(Dart_LibraryTag tag,
- const Object& arg1,
- const Object& arg2);
bool HasDeferredLoadHandler() const {
return group()->deferred_load_handler() != nullptr;
}
diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc
index 00ceb7d..9e6e614 100644
--- a/runtime/vm/kernel_binary.cc
+++ b/runtime/vm/kernel_binary.cc
@@ -194,18 +194,18 @@
std::unique_ptr<Program> Program::ReadFromFile(
const char* script_uri, const char** error /* = nullptr */) {
Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
+ auto isolate_group = thread->isolate_group();
if (script_uri == NULL) {
return nullptr;
}
- if (!isolate->HasTagHandler()) {
+ if (!isolate_group->HasTagHandler()) {
return nullptr;
}
std::unique_ptr<kernel::Program> kernel_program;
const String& uri = String::Handle(String::New(script_uri));
- const Object& ret = Object::Handle(
- isolate->CallTagHandler(Dart_kKernelTag, Object::null_object(), uri));
+ const Object& ret = Object::Handle(isolate_group->CallTagHandler(
+ Dart_kKernelTag, Object::null_object(), uri));
if (ret.IsExternalTypedData()) {
const auto& typed_data = ExternalTypedData::Handle(
thread->zone(), ExternalTypedData::RawCast(ret.ptr()));
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc
index 168cb76..9eab978 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -559,13 +559,12 @@
is_static_object.type = Dart_CObject_kBool;
is_static_object.value.as_bool = is_static;
- auto isolate = thread->isolate();
auto isolate_group = thread->isolate_group();
auto source = isolate_group->source();
Dart_CObject isolate_id;
isolate_id.type = Dart_CObject_kInt64;
- isolate_id.value.as_int64 = static_cast<int64_t>(isolate->main_port());
+ isolate_id.value.as_int64 = static_cast<int64_t>(isolate_group->id());
intptr_t num_dills = 0;
if (source->kernel_buffer != nullptr) {
@@ -756,16 +755,16 @@
// compilation logic out of CreateIsolateAndSetupHelper and into
// IsolateSetupHelper in main.cc.
auto thread = Thread::Current();
- auto isolate = thread != nullptr ? thread->isolate() : nullptr;
auto isolate_group = thread != nullptr ? thread->isolate_group() : nullptr;
if (incremental_compile) {
- ASSERT(isolate != NULL);
+ ASSERT(isolate_group != nullptr);
}
Dart_CObject isolate_id;
isolate_id.type = Dart_CObject_kInt64;
- isolate_id.value.as_int64 =
- isolate != nullptr ? static_cast<int64_t>(isolate->main_port()) : 0;
+ isolate_id.value.as_int64 = isolate_group != nullptr
+ ? static_cast<int64_t>(isolate_group->id())
+ : 0;
Dart_CObject message;
message.type = Dart_CObject_kArray;
@@ -1155,7 +1154,8 @@
Dart_KernelCompilationVerbosityLevel_Error);
}
-void KernelIsolate::NotifyAboutIsolateShutdown(const Isolate* isolate) {
+void KernelIsolate::NotifyAboutIsolateGroupShutdown(
+ const IsolateGroup* isolate_group) {
if (!KernelIsolate::IsRunning()) {
return;
}
@@ -1170,8 +1170,7 @@
Dart_CObject isolate_id;
isolate_id.type = Dart_CObject_kInt64;
- isolate_id.value.as_int64 =
- isolate != NULL ? static_cast<int64_t>(isolate->main_port()) : 0;
+ isolate_id.value.as_int64 = static_cast<int64_t>(isolate_group->id());
Dart_CObject message;
message.type = Dart_CObject_kArray;
diff --git a/runtime/vm/kernel_isolate.h b/runtime/vm/kernel_isolate.h
index 438e883..2ba4f2c 100644
--- a/runtime/vm/kernel_isolate.h
+++ b/runtime/vm/kernel_isolate.h
@@ -79,7 +79,8 @@
static Dart_KernelCompilationResult ListDependencies();
- static void NotifyAboutIsolateShutdown(const Isolate* isolate);
+ static void NotifyAboutIsolateGroupShutdown(
+ const IsolateGroup* isolate_group);
static void AddExperimentalFlag(const char* value);
static bool GetExperimentalFlag(ExperimentalFeature feature);
@@ -115,7 +116,8 @@
static bool IsRunning() { return false; }
static void Shutdown() {}
static bool IsKernelIsolate(const Isolate* isolate) { return false; }
- static void NotifyAboutIsolateShutdown(const Isolate* isolate) {}
+ static void NotifyAboutIsolateGroupShutdown(
+ const IsolateGroup* isolate_group) {}
static bool GetExperimentalFlag(const char* value) { return false; }
protected:
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 977686f..7dc46ad 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -704,13 +704,13 @@
void KernelLoader::LoadNativeExtension(const Library& library,
const String& uri_path) {
#if !defined(DART_PRECOMPILER)
- if (!I->HasTagHandler()) {
+ if (!IG->HasTagHandler()) {
H.ReportError("no library handler registered.");
}
I->BlockClassFinalization();
const auto& result = Object::Handle(
- Z, I->CallTagHandler(Dart_kImportExtensionTag, library, uri_path));
+ Z, IG->CallTagHandler(Dart_kImportExtensionTag, library, uri_path));
I->UnblockClassFinalization();
if (result.IsError()) {
diff --git a/runtime/vm/os_fuchsia.cc b/runtime/vm/os_fuchsia.cc
index e79827b..674bdd5 100644
--- a/runtime/vm/os_fuchsia.cc
+++ b/runtime/vm/os_fuchsia.cc
@@ -10,8 +10,10 @@
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
-#include <fuchsia/deprecatedtimezone/cpp/fidl.h>
+#include <fuchsia/intl/cpp/fidl.h>
#include <lib/async-loop/default.h>
#include <lib/async-loop/loop.h>
#include <lib/async/default.h>
@@ -22,21 +24,49 @@
#include <zircon/process.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/object.h>
-#include <zircon/time.h>
#include <zircon/threads.h>
+#include <zircon/time.h>
#include <zircon/types.h>
+#include <set>
+
+#include "unicode/errorcode.h"
+#include "unicode/timezone.h"
+#include "unicode/umachine.h"
+
#include "platform/assert.h"
+#include "platform/syslog.h"
#include "platform/utils.h"
+#include "vm/lockers.h"
+#include "vm/os_thread.h"
#include "vm/zone.h"
namespace {
+using dart::Mutex;
+using dart::MutexLocker;
+using dart::Syslog;
+using dart::Zone;
+
+// This is the default timezone returned if it could not be obtained. For
+// Fuchsia, the default device timezone is always UTC.
+static const char kDefaultTimezone[] = "UTC";
+
+static constexpr int32_t kMsPerSec = 1000;
+
// The data directory containing ICU timezone data files.
static constexpr char kICUTZDataDir[] = "/config/data/tzdata/icu/44/le";
+// This is the general OK status.
+static constexpr int32_t kOk = 0;
+
+// This status means that the error code is not initialized yet ("set" was not
+// yet called). Error codes are usually either 0 (kOk), or negative.
+static constexpr int32_t kUninitialized = 1;
+
// The status codes for tzdata file open and read.
enum class TZDataStatus {
+ // The operation completed without error.
OK = 0,
// The open call for the tzdata file did not succeed.
COULD_NOT_OPEN = -1,
@@ -46,6 +76,8 @@
// Adds a facility for introspecting timezone data errors. Allows insight into
// the internal state of the VM even if error reporting facilities fail.
+//
+// Under normal operation, all metric values below should be zero.
class InspectMetrics {
public:
// Does not take ownership of inspector.
@@ -53,9 +85,27 @@
: inspector_(inspector),
root_(inspector_->GetRoot()),
metrics_(root_.CreateChild("os")),
- dst_status_(metrics_.CreateInt("dst_status", 0)),
- tz_data_status_(metrics_.CreateInt("tz_data_status", 0)),
- tz_data_close_status_(metrics_.CreateInt("tz_data_close_status", 0)) {}
+ dst_status_(metrics_.CreateInt("dst_status", kUninitialized)),
+ tz_data_status_(metrics_.CreateInt("tz_data_status", kUninitialized)),
+ tz_data_close_status_(
+ metrics_.CreateInt("tz_data_close_status", kUninitialized)),
+ get_profile_status_(
+ metrics_.CreateInt("get_profile_status", kUninitialized)),
+ profiles_timezone_content_status_(
+ metrics_.CreateInt("timezone_content_status", kOk)),
+ num_get_profile_calls_(metrics_.CreateInt("num_get_profile_calls", 0)),
+ num_on_change_calls_(metrics_.CreateInt("num_on_change_calls", 0)),
+ num_intl_provider_errors_(
+ metrics_.CreateInt("num_intl_provider_errors", 0)) {}
+
+ // Registers a single call to GetProfile callback.
+ void RegisterGetProfileCall() { num_get_profile_calls_.Add(1); }
+
+ // Registers a single call to OnChange callback.
+ void RegisterOnChangeCall() { num_on_change_calls_.Add(1); }
+
+ // Registers a provider error.
+ void RegisterIntlProviderError() { num_intl_provider_errors_.Add(1); }
// Sets the last status code for DST offset calls.
void SetDSTOffsetStatus(zx_status_t status) {
@@ -69,6 +119,17 @@
tz_data_close_status_.Set(status);
}
+ // Sets the last status code for the call to PropertyProvider::GetProfile.
+ void SetProfileStatus(zx_status_t status) {
+ get_profile_status_.Set(static_cast<int32_t>(status));
+ }
+
+ // Sets the last status seen while examining timezones returned from
+ // PropertyProvider::GetProfile.
+ void SetTimeZoneContentStatus(zx_status_t status) {
+ profiles_timezone_content_status_.Set(static_cast<int32_t>(status));
+ }
+
private:
// The inspector that all metrics are being reported into.
inspect::Inspector* inspector_;
@@ -87,11 +148,166 @@
// The return code for the close() call for tzdata files.
inspect::IntProperty tz_data_close_status_;
+
+ // The return code of the GetProfile call in GetTimeZoneName. If this is
+ // nonzero, then os_fuchsia.cc reported a default timezone as a fallback.
+ inspect::IntProperty get_profile_status_;
+
+ // U_ILLEGAL_ARGUMENT_ERROR(=1) if timezones read from ProfileProvider were
+ // incorrect. Otherwise 0. If this metric reports U_ILLEGAL_ARGUMENT_ERROR,
+ // the os_fuchsia.cc module reported a default timezone as a fallback.
+ inspect::IntProperty profiles_timezone_content_status_;
+
+ // Keeps a number of get_profile update calls.
+ inspect::IntProperty num_get_profile_calls_;
+
+ // Number of "on change" callback calls.
+ inspect::IntProperty num_on_change_calls_;
+
+ // Keeps a number of errors encountered in intl provider.
+ inspect::IntProperty num_intl_provider_errors_;
};
+// Thread-safe storage for the current timezone name.
+//
+// Keeps an up to date timezone cache, updating if needed through the
+// asynchronous update interface. Access to this class is thread-safe.
+class TimezoneName final {
+ public:
+ // Creates a new instance of TimezoneName. Does not take ownership of
+ // metrics.
+ static std::shared_ptr<TimezoneName> New(
+ fuchsia::intl::PropertyProviderPtr proxy,
+ std::weak_ptr<InspectMetrics> metrics) {
+ auto timezone_name =
+ std::make_shared<TimezoneName>(std::move(proxy), metrics);
+ timezone_name->InitHandlers(timezone_name);
+ return timezone_name;
+ }
+
+ TimezoneName(fuchsia::intl::PropertyProviderPtr proxy,
+ std::weak_ptr<InspectMetrics> metrics)
+ : m_(),
+ metrics_(std::move(metrics)),
+ proxy_(std::move(proxy)),
+ timezone_name_(kDefaultTimezone) {
+ ASSERT(metrics_.lock() != nullptr);
+ }
+
+ // Gets the current timezone name. Repeated calls may retrieve updated
+ // values.
+ std::string Get() const {
+ MutexLocker lock(&m_);
+ // Returns a copy, to avoid a data race with async updates.
+ return timezone_name_;
+ }
+
+ private:
+ // Sets the event handlers in this resolver. Intended to resolve a circular
+ // reference between the shared timezone name and this.
+ void InitHandlers(std::shared_ptr<TimezoneName> timezone_name) {
+ ASSERT(timezone_name.get() == this);
+ timezone_name->proxy_.set_error_handler(
+ [weak_this =
+ std::weak_ptr<TimezoneName>(timezone_name)](zx_status_t status) {
+ if (!weak_this.expired()) {
+ weak_this.lock()->ErrorHandler(status);
+ }
+ });
+ timezone_name->proxy_.events().OnChange =
+ [weak_this = std::weak_ptr<TimezoneName>(timezone_name)]() {
+ if (!weak_this.expired()) {
+ weak_this.lock()->OnChangeCallback();
+ }
+ };
+ timezone_name->proxy_->GetProfile(
+ [weak_this = std::weak_ptr<TimezoneName>(timezone_name)](
+ fuchsia::intl::Profile profile) {
+ if (!weak_this.expired()) {
+ weak_this.lock()->GetProfileCallback(std::move(profile));
+ }
+ });
+ }
+
+ // Called on a profile provider error in the context of the event loop
+ // thread.
+ void ErrorHandler(zx_status_t status) {
+ MutexLocker lock(&m_);
+ WithMetrics([status](std::shared_ptr<InspectMetrics> metrics) {
+ metrics->SetProfileStatus(status);
+ metrics->RegisterIntlProviderError();
+ });
+ }
+
+ // Called when an OnChange event is received in the context of the event loop
+ // thread. The only action here is to trigger an asynchronous update of the
+ // intl profile.
+ void OnChangeCallback() {
+ MutexLocker lock(&m_);
+ WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
+ metrics->RegisterOnChangeCall();
+ });
+ proxy_->GetProfile([this](fuchsia::intl::Profile profile) {
+ this->GetProfileCallback(std::move(profile));
+ });
+ }
+
+ // Called when a GetProfile async request is resolved, in the context of the
+ // event loop thread.
+ void GetProfileCallback(fuchsia::intl::Profile profile) {
+ MutexLocker lock(&m_);
+ WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
+ metrics->RegisterGetProfileCall();
+ });
+ const std::vector<fuchsia::intl::TimeZoneId>& timezones =
+ profile.time_zones();
+ if (timezones.empty()) {
+ WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
+ metrics->SetTimeZoneContentStatus(U_ILLEGAL_ARGUMENT_ERROR);
+ });
+ // Empty timezone array is not up to fuchsia::intl spec. The serving
+ // endpoint is broken and should be fixed.
+ Syslog::PrintErr("got empty timezone value\n");
+ return;
+ }
+ WithMetrics([](std::shared_ptr<InspectMetrics> metrics) {
+ metrics->SetProfileStatus(ZX_OK);
+ metrics->SetTimeZoneContentStatus(ZX_OK);
+ });
+
+ timezone_name_ = timezones[0].id;
+ }
+
+ // Runs the provided function only on valid metrics.
+ void WithMetrics(std::function<void(std::shared_ptr<InspectMetrics> m)> f) {
+ std::shared_ptr<InspectMetrics> l = metrics_.lock();
+ if (l != nullptr) {
+ f(l);
+ }
+ }
+
+ // Guards timezone_name_ because the callbacks will be called in an
+ // asynchronous thread.
+ mutable Mutex m_;
+
+ // Used to keep tally on the update events. Not owned.
+ std::weak_ptr<InspectMetrics> metrics_;
+
+ // A client-side proxy for a connection to the property provider service.
+ fuchsia::intl::PropertyProviderPtr proxy_;
+
+ // Caches the current timezone name. This is updated asynchronously through
+ // GetProfileCallback.
+ std::string timezone_name_;
+};
+
+// The timezone names encountered so far. The timezone names must live forever.
+std::set<const std::string> timezone_names;
+
// Initialized on OS:Init(), deinitialized on OS::Cleanup.
std::unique_ptr<sys::ComponentInspector> component_inspector;
-std::unique_ptr<InspectMetrics> metrics;
+std::shared_ptr<InspectMetrics> metrics;
+std::shared_ptr<TimezoneName> timezone_name;
async_loop_t* message_loop = nullptr;
// Initializes the source of timezone data if available. Timezone data file in
@@ -153,35 +369,57 @@
// Putting this hack right now due to CP-120 as I need to remove
// component:ConnectToEnvironmentServices and this is the only thing that is
// blocking it and FL-98 will take time.
-static fuchsia::deprecatedtimezone::TimezoneSyncPtr tz;
+static fuchsia::intl::PropertyProviderPtr property_provider;
static zx_status_t GetLocalAndDstOffsetInSeconds(int64_t seconds_since_epoch,
int32_t* local_offset,
int32_t* dst_offset) {
- zx_status_t status = tz->GetTimezoneOffsetMinutes(seconds_since_epoch * 1000,
- local_offset, dst_offset);
- metrics->SetDSTOffsetStatus(status);
- if (status != ZX_OK) {
- return status;
+ const char* timezone_id = OS::GetTimeZoneName(seconds_since_epoch);
+ std::unique_ptr<icu::TimeZone> timezone(
+ icu::TimeZone::createTimeZone(timezone_id));
+ UErrorCode error = U_ZERO_ERROR;
+ const auto ms_since_epoch =
+ static_cast<UDate>(kMsPerSec * seconds_since_epoch);
+ // The units of time that local_offset and dst_offset are returned from this
+ // function is, usefully, not documented, but it seems that the units are
+ // milliseconds. Add these variables here for clarity.
+ int32_t local_offset_ms = 0;
+ int32_t dst_offset_ms = 0;
+ timezone->getOffset(ms_since_epoch, /*local_time=*/0, local_offset_ms,
+ dst_offset_ms, error);
+ metrics->SetDSTOffsetStatus(error);
+ if (error != U_ZERO_ERROR) {
+ icu::ErrorCode icu_error;
+ icu_error.set(error);
+ Syslog::PrintErr("could not get DST offset: %s\n", icu_error.errorName());
+ return ZX_ERR_INTERNAL;
}
- *local_offset *= 60;
- *dst_offset *= 60;
+ // We must return offset in seconds, so convert.
+ *local_offset = local_offset_ms / kMsPerSec;
+ *dst_offset = dst_offset_ms / kMsPerSec;
return ZX_OK;
}
+// Returns a C string with the time zone name. This module retains the
+// ownership of the pointer.
const char* OS::GetTimeZoneName(int64_t seconds_since_epoch) {
- // TODO(abarth): Handle time zone changes.
- static const auto* tz_name = new std::string([] {
- std::string result;
- tz->GetTimezoneId(&result);
- return result;
- }());
- return tz_name->c_str();
+ ASSERT(timezone_name != nullptr);
+
+ // Sadly, since we do not know how long the timezone name will be needed, we
+ // can not ever deallocate it. So instead, we put it into a a set that will
+ // not move it around in memory and return a pointer to it. Since the number
+ // of timezones is finite, this ensures that the memory taken up by timezones
+ // does not grow indefinitely, even if we end up retaining all the timezones
+ // there are.
+ const auto i = timezone_names.insert(timezone_name->Get());
+ ASSERT(i.first != timezone_names.end());
+ return i.first->c_str();
}
int OS::GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch) {
- int32_t local_offset, dst_offset;
- zx_status_t status = GetLocalAndDstOffsetInSeconds(
+ int32_t local_offset = 0;
+ int32_t dst_offset = 0;
+ const zx_status_t status = GetLocalAndDstOffsetInSeconds(
seconds_since_epoch, &local_offset, &dst_offset);
return status == ZX_OK ? local_offset + dst_offset : 0;
}
@@ -211,7 +449,7 @@
}
int64_t OS::GetCurrentMonotonicMicros() {
- int64_t ticks = GetCurrentMonotonicTicks();
+ const int64_t ticks = GetCurrentMonotonicTicks();
ASSERT(GetCurrentMonotonicFrequency() == kNanosecondsPerSecond);
return ticks / kNanosecondsPerMicrosecond;
}
@@ -231,6 +469,9 @@
return -1;
}
+// The timezone names encountered so far. The timezone names must live forever.
+std::set<const std::string> timezone_names;
+
// TODO(5411554): May need to hoist these architecture dependent code
// into a architecture specific file e.g: os_ia32_fuchsia.cc
intptr_t OS::ActivationFrameAlignment() {
@@ -300,7 +541,7 @@
va_end(measure_args);
char* buffer;
- if (zone) {
+ if (zone != nullptr) {
buffer = zone->Alloc<char>(len + 1);
} else {
buffer = reinterpret_cast<char*>(malloc(len + 1));
@@ -364,19 +605,22 @@
sys::ComponentContext* context = dart::ComponentContext();
component_inspector = std::make_unique<sys::ComponentInspector>(context);
- metrics = std::make_unique<InspectMetrics>(component_inspector->inspector());
+ metrics = std::make_shared<InspectMetrics>(component_inspector->inspector());
InitializeTZData();
- context->svc()->Connect(tz.NewRequest());
+ auto services = sys::ServiceDirectory::CreateFromNamespace();
+ services->Connect(property_provider.NewRequest());
+
+ timezone_name = TimezoneName::New(std::move(property_provider), metrics);
}
void OS::Cleanup() {
if (message_loop != nullptr) {
async_loop_shutdown(message_loop);
}
-
- metrics = nullptr;
- component_inspector = nullptr;
+ timezone_name.reset();
+ metrics.reset();
+ component_inspector.reset();
if (message_loop != nullptr) {
// Check message_loop is still the default dispatcher before clearing it.
diff --git a/tools/VERSION b/tools/VERSION
index cfed773..a6a98c2 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 48
+PRERELEASE 49
PRERELEASE_PATCH 0
\ No newline at end of file