By Michael Thomsen, Dart & Flutter Product Manager, Google

We have officially released version 2.15 of the Dart SDK, which includes fast concurrency worker ISOLATE, new constructor tear-off language features, improved Dart: Core library enumeration support, new features related to package publishers, And so on.

Fast concurrency of the worker ISOLATE

Today, almost all modern devices use multi-core cpus that can perform multiple tasks in parallel. For most Dart programs, the use of these kernels is transparent to the developer: By default, the Dart runtime system runs all Dart code on a single kernel, but uses other kernels to perform system-level tasks, such as asynchronous input/output, including writing files or calling networks.

However, your own Dart code might also need to run concurrently. For example, you might need to show a continuous animation while performing a long-running task, such as parsing a large JSON file. If the extra tasks take too long, the interface can get stuck or delayed. If these additional tasks are moved to a separate kernel, the animation can continue to run undisturbed on the main execution thread.

Dart’s concurrency model is based on ISOLATE, a separate execution unit that is isolated from each other in order to avoid the large number of concurrent programming errors associated with shared memory, such as race conditions such as data contention. Dart avoids these errors by disallowing the sharing of any mutable objects between isolates and using messaging to exchange state between isolates. In Dart 2.15, we made a number of substantial improvements to ISOLATE.

We first redesigned and implemented the way the ISOLATE worked, introducing a new concept: the ISOLATE Group. Isolate The Isolate in the Isolate group shares various internal data structures that represent running programs. This makes the individual isolates in the group much more portable. Today, starting an additional ISOLATE in an existing ISOLATE is over 100 times faster than before, and the resulting ISOLATE consumes 10 to 100 times less memory, because there is no need to initialize the program structure.

Although the ISOLATE groups still prevented sharing access to mutable objects between the isolates, they also had more functionality due to the fact that the ISOLATE groups used the shared heap implementation. We can pass objects from one ISOLATE to another, which can be used to perform a worker ISOLATE that returns a large amount of memory data. For example, the worker ISOLATE gets the data through a network call, parses the data into a large JSON object graph, and then returns the JSON graph to the main ISOLATE. Prior to Dart 2.15, this operation required deep copying, which could cause the interface to stall if it took longer than the frame budget.

In Dart 2.15, the worker ISOLATE can call isolate.exit (), passing the result as an argument. The Dart runtime then passes the memory data containing the results from the worker ISOLATE to the master ISOLATE without replication, and the master ISOLATE can receive the results for a fixed amount of time. We have updated the compute() utility function in Flutter 2.8 to take advantage of isolate.exit (). If you are already using Compute (), you will automatically get these performance improvements after upgrading to Flutter 2.8.

Finally, we redesigned the implementation of the ISOLATE messaging mechanism, which increased the speed of medium and small messages by about 8 times. Sending messages is significantly faster, while receiving messages is almost always done in a constant amount of time. In addition, we expanded the types of objects that isolate can send to each other, adding support for function types, closures, and stack trace objects. Refer to the API documentation for sendport.send () for details.

For more information on how to use ISOLATE, see concurrency in Dart, the official documentation we added for Dart 2.15, and more code examples.

New language feature: constructor splitting

In Dart, you can create a function object with a function name that points to a function of another object. In the following example, the second line of the main() method demonstrates the syntax for pointing g to m.Green:

class Greeter {
  final String name;
  Greeter(this.name);

  void greet(String who) {
    print('$name says: Hello $who! '); }}void main() {
  final m = Greeter('Michael');
  final g = m.greet; // g holds a function pointer to m.greet.
  g('Leaf'); // Invokes and prints "Michael says: Hello Leaf!"
}
Copy the code

This type of function pointer (also known as function splitting) occurs frequently when using the Dart core library. Here is an example of calling foreach() on iterable by passing a pointer to a function:

final m = Greeter('Michael');
['Lasse'.'Bob'.'Erik'].forEach(m.greet);
// Prints "Michael says: Hello Lasse!" , "Michael says: Hello Bob!" .
// "Michael says: Hello Erik!"
Copy the code

In previous versions, the Dart SDK did not support splitting constructors for creation (language issue #216). This is a bit annoying because in many cases, such as when building a Flutter interface, constructor splitting is required. Starting with Dart 2.15, we support this syntax. Here is an example of building a Column widget with three Text widgets, passing a split of the Text constructor to the Column child by calling.map().

class FruitWidget extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return Column(
       children: ['Apple'.'Orange'].map(Text.new).toList()); }}Copy the code

Text.new refers to the default constructor of the Text class. You can also reference named constructors, such as.map(text.rich).

Related language change

In implementing constructor split, we also took the opportunity to fix some inconsistencies in the existing function pointer functionality. You can now specialize generic methods to create non-generic methods:

T id<T>(T value) => value;
var intId = id<int>; / / New in 2.15.
int Function(int) intId = id; / / the Pre - 2.15 workaround.
Copy the code

You can even specialize a generic function object to create a non-generic function object:

const fo = id; // Tear off `id`, creating a function object.
const c1 = fo<int>; / / New in 2.15; error before.
Copy the code

Finally, Dart 2.15 clears up type literals involving generics:

var y = List; // Already supported.
var z = List<int>; / / New in 2.15.
var z = typeOf<List<int> > ();/ / the Pre - 2.15 workaround.
Copy the code

Improved DART: Enumeration in the core library

We added a number of optimizations to the ENUMeration API of the DART: Core library (language issue #1511). Now you can get the String value for each enumerated value by.name:

enum MyEnum {
 one, two, three
}
void main() {
 print(MyEnum.one.name);  // Prints "one".
}
Copy the code

Enumeration values can also be found by name:

print(MyEnum.values.byName('two') == MyEnum.two);  // Prints "true".
Copy the code

Finally, you can get a mapping of all name-value pairs:

final map = MyEnum.values.asNameMap();
print(map['three'] == MyEnum.three);  // Prints "true".
Copy the code

See this Flutter PR to see examples of the use of these new apis.

Compression pointer

Dart 2.15 adds support for compressed Pointers so that the 64-bit SDK can use a more space-saving pointer representation if only 32-bit address space (up to 4 GB of memory) needs to be supported. Compressing the pointer significantly reduces memory footprint, and in internal testing of the Google Pay application, we found that the Dart heap was reduced in size by approximately 10%.

The compressed pointer means that more than 4 GB of available RAM cannot be handled, so this feature only exists in the CONFIGURATION options of the Dart SDK and can only be enabled by the Dart SDK’s embeddler when building the SDK. The Flutter SDK version 2.8 has enabled this configuration for Android builds and the Flutter team is considering enabling this configuration for iOS builds in a later release.

Dart DevTools is included with the Dart SDK

Previously, the Dart SDK did not provide the DevTools suite for debugging and performance tools, which you need to download separately. Starting with Dart 2.15, DevTools is also available when you download the Dart SDK without further installation steps. For more information about using DevTools in the Dart command line application, see the DevTools documentation.

New PUB feature for Package publishers

The Dart 2.15 SDK also adds two new features in the Dart pub developer command and pub.dev package repo.

First, a new security feature has been added for package publishers to detect publishers accidentally publishing secret, such as Cloud or CI credentials, in a Pub package. We decided to add leak detection after learning that thousands of Secret leaks were happening every day on the GitHub repo.

Leak detection is run as part of pre-publish validation in the DART pub publish command. If it detects a potential secret in a file it is about to publish, publish exits without publishing and prints the following output:

Publishing my_package 1.0.0 to https://pub.dartlang.org: Package validation found the following errors: * line 1, column 1 of lib/key.pem: Potential leak of Private Key detected. ╷ 1 │ chrysene -BEGIN Private Key - 2 │ 53 WMSN H0M6xpM2q + / 3 │ eYLdgtjgBd3DBmHtPilCkiFICXyaA8z9LkJ └ - END PRIVATE KEY - ╵ * line 2, column 23 of lib/my_package.dart: Potential leak of Google OAuth Refresh Token detected. ╷ 2 │ Final refreshToken = "1//042ys8uoFwZrkCgYIARAAGAQSNwF-L9IrXmFYE-sfKefSpoCnyqEcsHX97Y90KY-p8TPYPPnY2IPgRXdy0QeVw7URuF5u9oUeIF0";Copy the code

In rare cases, this detection can produce false positives that flag content or files that you actually intend to publish as potentially compromised. In these cases, you can add files to the licensed list.

Second, we have added another capability for publishers to undo published versions of the package. When a problematic package version is released, our usual recommendation is to release a new version with a minor upgrade to fix unexpected problems. But in rare cases, such as when you haven’t fixed these issues or when you accidentally release a major release when you intended to release only a minor release, you can use the new Package undo feature as a last resort. This feature is provided in the administration interface of pub.dev:

After a package version is withdrawn, the Pub client will no longer parse that version in Pub GET or Pub Upgrade. If a developer has already parsed the withdrawn version (and exists in their pubspec.lock file), they will see a warning the next time they run pub:

$dart pub get considerations dependencies... Mypkg 0.0.181-buggy (retracted, 0.0.182-fixed available) Got dependencies!Copy the code

Security Analysis for Bidirectional Unicode Character Detection (CVE-2021-22567)

A general-purpose programming language vulnerability (CVE-2021-42574) involving bidirectional Unicode characters was recently discovered. This vulnerability affects most modern programming languages that support Unicode. The Dart source code below demonstrates this problem:

main() {
 final accessLevel = 'user';
 if (accessLevel == 'user .⁦// Check if admin⁩ ⁦') {
   print('You are a regular user.');
 } else {
   print('You are an admin.'); }}Copy the code

You might think that the program would print You are a regular user., but it actually prints You are an admin.! You can exploit this vulnerability by using strings that contain bidirectional Unicode characters. These bidirectional characters are for text on the same line and can change the orientation of text from left to right to right to left and vice versa. Bidirectional character text is rendered on the screen quite differently from the actual text content. You can take a closer look at this GitHub GIST example.

Mitigation measures for this vulnerability include using tools that detect bidirectional Unicode characters (editors, code review tools, etc.) so that developers can find them and use them knowingly. The GitHub GIST file viewer mentioned above is an example of a tool that finds these characters.

Dart 2.15 introduces further mitigation measures (Dart safety recommendation CVE-2021-22567). Dart analyzer now scans bidirectional Unicode characters and flags any use of them:

$ dart analyze
Analyzing cvetest...                   2.6s
info • bin/cvetest.dart:4:27 • The Unicode code point 'U+202E'
      changes the appearance of text from how it's interpreted
      by the compiler. Try removing the code point or using the
      Unicode escape sequence '\u202E'. •
      text_direction_code_point_in_literal
Copy the code

We recommend replacing these characters with Unicode escape sequences so that they can be displayed in any text editor or viewer. Or, if you do use these characters properly, you can disable warnings by adding an override statement before a line of code that uses them:

// ignore: text_direction_code_point_in_literal
Copy the code

Pub. dev Credential Vulnerability when using third-party PUB server (CVE-2021-22568)

We also released a second Dart safety recommendation related to pub.dev: CVE-2021-22568. This recommendation is for package publishers who may publish packages to third-party PUB Package servers, such as private or in-house package servers. Developers who only publish the package to the public pub.dev repo (standard configuration) are not affected by this vulnerability.

If you have already published the package to a third-party repO, the vulnerability is that the OAuth2 temporary (one hour) access token used for authentication at a third-party REPO could be misused to authenticate on the public pub.dev repo. So a malicious third-party PUB server could use access tokens to impersonate you on pub.dev and publish the package. If you have published your package to an untrusted third party package repo, consider reviewing all activity of your account on pub.dev public Package repo. We recommend that you use the pub.dev activity log to view this.

The last

We hope you enjoyed the new features in Dart 2.15 that have been rolled out. This is our last release of the year, and we’d like to take this opportunity to express our appreciation for the wonderful Dart ecosystem. Thank you for your valuable feedback, and for your continued support, and for the thousands of packages that have been published on pub.dev over the past year that have enriched our ecosystem. We can’t wait to get back to work next year, and we have a lot of exciting content planned for 2022. I wish you all a happy New Year and enjoy the upcoming holidays!