Version 2.18.0-41.0.dev
Merge commit '6cea65bab7bba76b492b81a4372a5b6a4b07ea99' into 'dev'
diff --git a/DEPS b/DEPS
index f68d086..db75ce7 100644
--- a/DEPS
+++ b/DEPS
@@ -54,7 +54,7 @@
# Checkout Android dependencies only on Mac and Linux.
"download_android_deps":
- "(host_os == mac or host_os == linux) and host_cpu == x64",
+ "host_os == mac or (host_os == linux and host_cpu == x64)",
# Checkout extra javascript engines for testing or benchmarking.
# d8, the V8 shell, is always checked out.
@@ -144,7 +144,7 @@
"root_certificates_rev": "692f6d6488af68e0121317a9c2c9eb393eb0ee50",
"rust_revision": "b7856f695d65a8ebc846754f97d15814bcb1c244",
"shelf_packages_handler_rev": "78302e67c035047e6348e692b0c1182131f0fe35",
- "shelf_proxy_rev": "ccd311f64d8689e7a145d703ba267975d6df9e28",
+ "shelf_proxy_rev": "124615d0614b38814970aa9638725d9d6b435268",
"shelf_rev": "78ac724a7944700340a3cef28c84bccbe62e9367",
"shelf_static_rev": "202ec1a53c9a830c17cf3b718d089cf7eba568ad",
"shelf_web_socket_rev": "24fb8a04befa75a94ac63a27047b231d1a22aab4",
@@ -531,7 +531,7 @@
Var("dart_root") + "/third_party/android_tools/ndk": {
"packages": [
{
- "package": "flutter/android/ndk/${{platform}}",
+ "package": "flutter/android/ndk/${{os}}-amd64",
"version": "version:r21.0.6113669"
}
],
@@ -542,7 +542,7 @@
Var("dart_root") + "/third_party/android_tools/sdk/build-tools": {
"packages": [
{
- "package": "flutter/android/sdk/build-tools/${{platform}}",
+ "package": "flutter/android/sdk/build-tools/${{os}}-amd64",
"version": "version:30.0.1"
}
],
@@ -553,7 +553,7 @@
Var("dart_root") + "/third_party/android_tools/sdk/platform-tools": {
"packages": [
{
- "package": "flutter/android/sdk/platform-tools/${{platform}}",
+ "package": "flutter/android/sdk/platform-tools/${{os}}-amd64",
"version": "version:29.0.2"
}
],
@@ -575,7 +575,7 @@
Var("dart_root") + "/third_party/android_tools/sdk/tools": {
"packages": [
{
- "package": "flutter/android/sdk/tools/${{platform}}",
+ "package": "flutter/android/sdk/tools/${{os}}-amd64",
"version": "version:26.1.1"
}
],
diff --git a/benchmarks/Startup/dart/Startup.dart b/benchmarks/Startup/dart/Startup.dart
new file mode 100644
index 0000000..49889fb
--- /dev/null
+++ b/benchmarks/Startup/dart/Startup.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2022, 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.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:compiler/src/dart2js.dart' as dart2js;
+
+Future<void> main(List<String> args) async {
+ if (args.contains('--child')) {
+ return;
+ }
+
+ // Include dart2js and prevent tree-shaking to make this program have a
+ // non-trival snapshot size.
+ if (args.contains('--train')) {
+ args.remove('--train');
+ return dart2js.main(args);
+ }
+
+ var tempDir;
+ var events;
+ try {
+ tempDir = await Directory.systemTemp.createTemp();
+ final timelinePath =
+ tempDir.uri.resolve('Startup-timeline.json').toFilePath();
+ final p = await Process.run(Platform.executable, [
+ ...Platform.executableArguments,
+ '--timeline_recorder=file:$timelinePath',
+ '--timeline_streams=VM,Isolate,Embedder',
+ Platform.script.toFilePath(),
+ '--child'
+ ]);
+ if (p.exitCode != 0) {
+ print(p.stdout);
+ print(p.stderr);
+ throw 'Child process failed: ${p.exitCode}';
+ }
+
+ events = jsonDecode(await File(timelinePath).readAsString());
+ } finally {
+ await tempDir.delete(recursive: true);
+ }
+
+ var mainIsolateId;
+ for (final event in events) {
+ if (event['name'] == 'InitializeIsolate' &&
+ event['args']['isolateName'] == 'main') {
+ mainIsolateId = event['args']['isolateId'];
+ }
+ }
+ if (mainIsolateId == null) {
+ throw 'Could not determine main isolate';
+ }
+
+ void report(String name, String isolateId) {
+ var filtered = events.where((event) => event['name'] == name);
+ if (isolateId != null) {
+ filtered =
+ filtered.where((event) => event['args']['isolateId'] == isolateId);
+ }
+ var micros;
+ final durations = filtered.where((event) => event['ph'] == 'X');
+ final begins = filtered.where((event) => event['ph'] == 'B');
+ final ends = filtered.where((event) => event['ph'] == 'E');
+ if (durations.length == 1 && begins.length == 0 && ends.length == 0) {
+ micros = durations.single['dur'];
+ } else if (durations.length == 0 &&
+ begins.length == 1 &&
+ ends.length == 1) {
+ micros = ends.single['ts'] - begins.single['ts'];
+ } else {
+ print(durations.toList());
+ print(begins.toList());
+ print(ends.toList());
+ throw '$name is missing or ambiguous';
+ }
+ print('Startup.$name(RunTime): $micros us.');
+ }
+
+ report('CreateIsolateGroupAndSetupHelper', null);
+ report('InitializeIsolate', mainIsolateId);
+ report('ReadProgramSnapshot', mainIsolateId);
+}
diff --git a/benchmarks/Startup/dart2/Startup.dart b/benchmarks/Startup/dart2/Startup.dart
new file mode 100644
index 0000000..26fb07b
--- /dev/null
+++ b/benchmarks/Startup/dart2/Startup.dart
@@ -0,0 +1,87 @@
+// Copyright (c) 2022, 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.
+
+// @dart=2.9
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:compiler/src/dart2js.dart' as dart2js;
+
+Future<void> main(List<String> args) async {
+ if (args.contains('--child')) {
+ return;
+ }
+
+ // Include dart2js and prevent tree-shaking to make this program have a
+ // non-trival snapshot size.
+ if (args.contains('--train')) {
+ args.remove('--train');
+ return dart2js.main(args);
+ }
+
+ var tempDir;
+ var events;
+ try {
+ tempDir = await Directory.systemTemp.createTemp();
+ final timelinePath =
+ tempDir.uri.resolve('Startup-timeline.json').toFilePath();
+ final p = await Process.run(Platform.executable, [
+ ...Platform.executableArguments,
+ '--timeline_recorder=file:$timelinePath',
+ '--timeline_streams=VM,Isolate,Embedder',
+ Platform.script.toFilePath(),
+ '--child'
+ ]);
+ if (p.exitCode != 0) {
+ print(p.stdout);
+ print(p.stderr);
+ throw 'Child process failed: ${p.exitCode}';
+ }
+
+ events = jsonDecode(await File(timelinePath).readAsString());
+ } finally {
+ await tempDir.delete(recursive: true);
+ }
+
+ var mainIsolateId;
+ for (final event in events) {
+ if (event['name'] == 'InitializeIsolate' &&
+ event['args']['isolateName'] == 'main') {
+ mainIsolateId = event['args']['isolateId'];
+ }
+ }
+ if (mainIsolateId == null) {
+ throw 'Could not determine main isolate';
+ }
+
+ void report(String name, String isolateId) {
+ var filtered = events.where((event) => event['name'] == name);
+ if (isolateId != null) {
+ filtered =
+ filtered.where((event) => event['args']['isolateId'] == isolateId);
+ }
+ var micros;
+ final durations = filtered.where((event) => event['ph'] == 'X');
+ final begins = filtered.where((event) => event['ph'] == 'B');
+ final ends = filtered.where((event) => event['ph'] == 'E');
+ if (durations.length == 1 && begins.length == 0 && ends.length == 0) {
+ micros = durations.single['dur'];
+ } else if (durations.length == 0 &&
+ begins.length == 1 &&
+ ends.length == 1) {
+ micros = ends.single['ts'] - begins.single['ts'];
+ } else {
+ print(durations.toList());
+ print(begins.toList());
+ print(ends.toList());
+ throw '$name is missing or ambiguous';
+ }
+ print('Startup.$name(RunTime): $micros us.');
+ }
+
+ report('CreateIsolateGroupAndSetupHelper', null);
+ report('InitializeIsolate', mainIsolateId);
+ report('ReadProgramSnapshot', mainIsolateId);
+}
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 3889bb4..afb3a74 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -369,13 +369,13 @@
# default toolchain.
if (is_win) {
- # On windows we use the same toolchain for host and target by default.
if (is_clang) {
- host_toolchain = "//build/toolchain/win:clang_$current_cpu"
+ host_toolchain = "//build/toolchain/win:clang_$host_cpu"
+ set_default_toolchain("//build/toolchain/win:clang_$current_cpu")
} else {
- host_toolchain = "//build/toolchain/win:$current_cpu"
+ host_toolchain = "//build/toolchain/win:$host_cpu"
+ set_default_toolchain("//build/toolchain/win:$current_cpu")
}
- set_default_toolchain("$host_toolchain")
} else if (is_android) {
if (host_os == "linux") {
if (host_cpu == "x86" || host_cpu == "x64") {
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index c61d41a..f5def03 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -26,6 +26,9 @@
# architecture, which is different than the names GN uses.
if (host_cpu == "x64" || host_cpu == "x86") {
android_host_arch = "x86_64"
+ } else if (host_cpu == "arm64") {
+ # Run existing Android toolchain via Rosetta.
+ android_host_arch = "x86_64"
} else {
assert(false, "Need Android toolchain support for your build CPU arch.")
}
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 6cfcf26..f2984fb 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -67,6 +67,18 @@
"/GS", # Enable buffer security checking.
"/FS", # Preserve previous PDB behavior.
]
+
+ if (is_clang) {
+ if (current_cpu == "x86") {
+ cflags += [ "-m32" ]
+ } else if (current_cpu == "x64") {
+ cflags += [ "-m64" ]
+ } else if (current_cpu == "arm64") {
+ cflags += [ "--target=arm64-windows" ]
+ } else {
+ assert(false, "Unknown current_cpu: $current_cpu")
+ }
+ }
} else {
# Common GCC compiler flags setup.
# --------------------------------
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index daf26ed..98c2e23 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -34,14 +34,7 @@
# Linker flags for Windows SDK setup, this is applied only to EXEs and DLLs.
config("sdk_link") {
- if (current_cpu == "x64") {
- ldflags = [ "/MACHINE:X64" ]
- lib_dirs = [
- "$windows_sdk_path\Lib\winv6.3\um\x64",
- "$visual_studio_path\VC\lib\amd64",
- "$visual_studio_path\VC\atlmfc\lib\amd64",
- ]
- } else {
+ if (current_cpu == "x86") {
ldflags = [
"/MACHINE:X86",
"/SAFESEH", # Not compatible with x64 so use only for x86.
@@ -54,6 +47,29 @@
if (!is_asan) {
ldflags += [ "/largeaddressaware" ]
}
+ } else if (current_cpu == "x64") {
+ ldflags = [ "/MACHINE:X64" ]
+ lib_dirs = [
+ "$windows_sdk_path\Lib\winv6.3\um\x64",
+ "$visual_studio_path\VC\lib\amd64",
+ "$visual_studio_path\VC\atlmfc\lib\amd64",
+ ]
+ } else if (current_cpu == "arm") {
+ ldflags = [ "/MACHINE:ARM" ]
+ lib_dirs = [
+ "$windows_sdk_path\Lib\winv6.3\um\arm",
+ "$visual_studio_path\VC\lib\arm",
+ "$visual_studio_path\VC\atlmfc\lib\arm",
+ ]
+ } else if (current_cpu == "arm64") {
+ ldflags = [ "/MACHINE:ARM64" ]
+ lib_dirs = [
+ "$windows_sdk_path\Lib\winv6.3\um\arm64",
+ "$visual_studio_path\VC\lib\arm64",
+ "$visual_studio_path\VC\atlmfc\lib\arm64",
+ ]
+ } else {
+ assert(false, "Unknown current_cpu: $current_cpu")
}
}
@@ -67,6 +83,7 @@
"/ignore:4221",
"/ignore:4197", # Disable multiple Dart_True export warning.
"/NXCOMPAT",
+ "/DYNAMICBASE",
# Suggested by Microsoft Devrel to avoid
# LINK : fatal error LNK1248: image size (80000000)
@@ -74,30 +91,25 @@
# which started happening more regularly after VS2013 Update 4.
"/maxilksize:2147483647",
]
-
- # ASLR makes debugging with windbg difficult because Chrome.exe and
- # Chrome.dll share the same base name. As result, windbg will name the
- # Chrome.dll module like chrome_<base address>, where <base address>
- # typically changes with each launch. This in turn means that breakpoints in
- # Chrome.dll don't stick from one launch to the next. For this reason, we
- # turn ASLR off in debug builds.
- if (is_debug) {
- ldflags += [ "/DYNAMICBASE:NO" ]
- } else {
- ldflags += [ "/DYNAMICBASE" ]
- }
}
# Subsystem -------------------------------------------------------------------
# This is appended to the subsystem to specify a minimum version.
-if (current_cpu == "x64") {
+if (current_cpu == "x86") {
+ # 5.01 = Windows XP.
+ subsystem_version_suffix = ",5.01"
+} else if (current_cpu == "x64") {
# The number after the comma is the minimum required OS version.
# 5.02 = Windows Server 2003.
subsystem_version_suffix = ",5.02"
+} else if (current_cpu == "arm") {
+ subsystem_version_suffix = ",6.02"
+} else if (current_cpu == "arm64") {
+ # Windows ARM64 requires Windows 10.
+ subsystem_version_suffix = ",10.0"
} else {
- # 5.01 = Windows XP.
- subsystem_version_suffix = ",5.01"
+ assert(false, "Unknown current_cpu: $current_cpu")
}
config("console") {
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
index f7b2587..d70d49e 100644
--- a/build/toolchain/win/BUILD.gn
+++ b/build/toolchain/win/BUILD.gn
@@ -3,12 +3,8 @@
# found in the LICENSE file.
declare_args() {
- # Path to the directory containing the VC binaries for the right
- # combination of host and target architectures. Currently only the
- # 64-bit host toolchain is supported, with either 32-bit or 64-bit targets.
- # If vc_bin_dir is not specified on the command line (and it normally
- # isn't), we will dynamically determine the right value to use at runtime.
- vc_bin_dir = ""
+ # Path to the clang toolchain.
+ clang_base_path = "//buildtools/win-x64/clang"
}
import("//build/config/win/visual_studio_version.gni")
@@ -17,53 +13,55 @@
# Should only be running on Windows.
assert(is_win)
+# Setup the Visual Studio state.
+#
+# Its arguments are the VS path and the compiler wrapper tool. It will write
+# "environment.x86" and "environment.x64" to the build directory and return a
+# list to us.
+
# This tool will is used as a wrapper for various commands below.
tool_wrapper_path = rebase_path("tool_wrapper.py", root_build_dir)
-# Setup the Visual Studio state.
-toolchain_data = exec_script("setup_toolchain.py",
- [
- visual_studio_path,
- windows_sdk_path,
- visual_studio_runtime_dirs,
- "win",
- current_cpu,
- "environment." + current_cpu,
- ],
- "scope")
-
-if (vc_bin_dir == "") {
- vc_bin_dir = toolchain_data.vc_bin_dir
-}
-
if (use_goma) {
goma_prefix = "$goma_dir/gomacc.exe "
} else {
goma_prefix = ""
}
-# Parameters:
-# current_cpu: current_cpu to pass as a build arg
-# environment: File name of environment file.
-template("msvc_toolchain") {
- env = invoker.environment
-
+if (current_toolchain == default_toolchain) {
if (is_debug) {
configuration = "Debug"
} else {
configuration = "Release"
}
- exec_script("../../vs_toolchain.py",
+ exec_script("//build/vs_toolchain.py",
[
"copy_dlls",
rebase_path(root_build_dir),
configuration,
- invoker.current_cpu,
+ target_cpu,
])
+}
- cl = invoker.cl
-
+# Parameters:
+# toolchain_args: Settings for the toolchain, including at least:
+# current_cpu: current_cpu to pass as a build arg
+# environment: File name of environment file.
+template("msvc_toolchain") {
toolchain(target_name) {
+ # When invoking this toolchain not as the default one, these args will be
+ # passed to the build. They are ignored when this is the default toolchain.
+ assert(defined(invoker.toolchain_args))
+ toolchain_args = {
+ if (defined(invoker.toolchain_args)) {
+ forward_variables_from(invoker.toolchain_args, "*")
+ }
+ }
+
+ env = invoker.environment
+
+ cl = invoker.cl
+
# Make these apply to all tools below.
lib_switch = ""
lib_dir_switch = "/LIBPATH:"
@@ -74,11 +72,7 @@
# TODO(brettw) enable this when GN support in the binary has been rolled.
#precompiled_header_type = "msvc"
pdbname = "{{target_out_dir}}/{{target_output_name}}_c.pdb"
- flags = ""
- if (invoker.current_cpu == "x86") {
- flags = "-m32"
- }
- command = "ninja -t msvc -e $env -- $cl $flags /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd$pdbname"
+ command = "ninja -t msvc -e $env -- $cl /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd$pdbname"
depsformat = "msvc"
description = "CC {{output}}"
outputs = [
@@ -96,7 +90,7 @@
# The PDB name needs to be different between C and C++ compiled files.
pdbname = "{{target_out_dir}}/{{target_output_name}}_cc.pdb"
flags = ""
- if (invoker.current_cpu == "x86") {
+ if (is_clang && invoker.current_cpu == "x86") {
flags = "-m32"
}
command = "ninja -t msvc -e $env -- $cl $flags /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd$pdbname"
@@ -109,7 +103,8 @@
}
tool("rc") {
- command = "$python_path $tool_wrapper_path rc-wrapper $env rc.exe {{defines}} {{include_dirs}} /fo{{output}} {{source}}"
+ command = "$python_path $tool_wrapper_path rc-wrapper $env rc.exe /nologo {{defines}} {{include_dirs}} /fo{{output}} {{source}}"
+ depsformat = "msvc"
outputs = [
"{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.res",
]
@@ -117,14 +112,17 @@
}
tool("asm") {
- if (invoker.current_cpu == "x64") {
- ml = "ml64.exe"
- x64 = "-D_ML64_X64"
+ if (toolchain_args.current_cpu == "x86") {
+ command = "$python_path $tool_wrapper_path asm-wrapper $env ml.exe {{defines}} {{include_dirs}} {{asmflags}} /c /Fo {{output}} {{source}}"
+ } else if (toolchain_args.current_cpu == "x64") {
+ command = "$python_path $tool_wrapper_path asm-wrapper $env ml64.exe -D_ML64_X64 {{defines}} {{include_dirs}} {{asmflags}} /c /Fo {{output}} {{source}}"
+ } else if (toolchain_args.current_cpu == "arm") {
+ command = "$python_path $tool_wrapper_path asm-wrapper $env armasm.exe {{include_dirs}} {{asmflags}} -o {{output}} {{source}}"
+ } else if (toolchain_args.current_cpu == "arm64") {
+ command = "$python_path $tool_wrapper_path asm-wrapper $env armasm64.exe {{include_dirs}} {{asmflags}} -o {{output}} {{source}}"
} else {
- ml = "ml.exe"
- x64 = ""
+ assert(false, "Unknown current_cpu: ${toolchain_args.current_cpu}")
}
- command = "$python_path $tool_wrapper_path asm-wrapper $env $ml $x64 {{defines}} {{include_dirs}} {{asmflags}} /c /Fo {{output}} {{source}}"
description = "ASM {{output}}"
outputs = [
"{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj",
@@ -148,22 +146,17 @@
}
tool("solink") {
- dllname = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" # e.g.
- # foo.dll
- libname = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.lib" # e.g.
- # foo.dll.lib
+ dllname = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" # e.g. foo.dll
+ libname =
+ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.lib" # e.g. foo.dll.lib
rspfile = "${dllname}.rsp"
link_command = "$python_path $tool_wrapper_path link-wrapper $env False link.exe /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:${dllname}.pdb @$rspfile"
# TODO(brettw) support manifests
- #manifest_command = "$python_path gyp-win-tool manifest-wrapper $env mt.exe -nologo -manifest $manifests -out:${dllname}.manifest"
+ #manifest_command = "$python_path $tool_wrapper_path manifest-wrapper $env mt.exe -nologo -manifest $manifests -out:${dllname}.manifest"
#command = "cmd /c $link_command && $manifest_command"
- # Force rebuild of the .lib-file(if it is being produced) because msvc
- # linker seems to keep it untouched sometimes even when .obj-files are
- # being updated.
- cleanup_lib_command = "$python_path $tool_wrapper_path delete-file $libname"
- command = "cmd /c $cleanup_lib_command && cmd /c $link_command"
+ command = link_command
default_output_extension = ".dll"
description = "LINK(DLL) {{output}}"
@@ -177,12 +170,12 @@
# The use of inputs_newline is to work around a fixed per-line buffer
# size in the linker.
rspfile_content = "{{libs}} {{solibs}} {{inputs_newline}} {{ldflags}}"
+
+ restat = true
}
tool("solink_module") {
- dllname =
- "{{output_dir}}/{{target_output_name}}{{output_extension}}" # e.g.
- # foo.dll
+ dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" # e.g. foo.dll
pdbname = "${dllname}.pdb"
rspfile = "${dllname}.rsp"
@@ -207,11 +200,12 @@
binary_output =
"{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
rspfile = "$binary_output.rsp"
+ pdbfile = "$binary_output.pdb"
- link_command = "$python_path $tool_wrapper_path link-wrapper $env False link.exe /nologo /OUT:$binary_output /PDB:$binary_output.pdb @$rspfile"
+ link_command = "$python_path $tool_wrapper_path link-wrapper $env False link.exe /nologo /OUT:$binary_output /PDB:$pdbfile @$rspfile"
# TODO(brettw) support manifests
- #manifest_command = "$python_path gyp-win-tool manifest-wrapper $env mt.exe -nologo -manifest $manifests -out:{{output}}.manifest"
+ #manifest_command = "$python_path $tool_wrapper_path manifest-wrapper $env mt.exe -nologo -manifest $manifests -out:{{output}}.manifest"
#command = "cmd /c $link_command && $manifest_command"
command = link_command
@@ -220,6 +214,7 @@
outputs = [
binary_output,
"{{root_out_dir}}/{{target_output_name}}.lib",
+ pdbfile,
]
# The use of inputs_newline is to work around a fixed per-line buffer
@@ -230,58 +225,61 @@
}
tool("stamp") {
- command = "$python_path $tool_wrapper_path stamp {{output}}"
+ command = "cmd /c type nul > \"{{output}}\""
description = "STAMP {{output}}"
}
tool("copy") {
- command = "$python_path $tool_wrapper_path recursive-mirror {{source}} {{output}}"
+ command =
+ "$python_path $tool_wrapper_path recursive-mirror {{source}} {{output}}"
description = "COPY {{source}} {{output}}"
}
+ }
+}
- # When invoking this toolchain not as the default one, these args will be
- # passed to the build. They are ignored when this is the default toolchain.
+template("win_toolchains") {
+ assert(defined(invoker.toolchain_arch))
+ toolchain_arch = invoker.toolchain_arch
+
+ win_toolchain_data = exec_script("setup_toolchain.py",
+ [
+ visual_studio_path,
+ windows_sdk_path,
+ visual_studio_runtime_dirs,
+ toolchain_arch,
+ ],
+ "scope")
+
+ msvc_toolchain(target_name) {
+ environment = "environment." + toolchain_arch
+ cl = "${goma_prefix}\"${win_toolchain_data.vc_bin_dir}/cl.exe\""
toolchain_args = {
- current_cpu = invoker.current_cpu
- if (defined(invoker.is_clang)) {
- is_clang = invoker.is_clang
+ if (defined(invoker.toolchain_args)) {
+ forward_variables_from(invoker.toolchain_args, "*")
}
+ current_cpu = toolchain_arch
+ is_clang = false
+ }
+ }
+ msvc_toolchain("clang_" + target_name) {
+ environment = "environment." + toolchain_arch
+ prefix = rebase_path("$clang_base_path/bin", root_build_dir)
+ cl = "${goma_prefix}$prefix/clang-cl.exe"
+ toolchain_args = {
+ if (defined(invoker.toolchain_args)) {
+ forward_variables_from(invoker.toolchain_args, "*")
+ }
+ current_cpu = toolchain_arch
+ is_clang = true
}
}
}
-# TODO(dpranke): Declare both toolchains all of the time when we
-# get it sorted out how we want to support them both in a single build.
-# Right now only one of these can be enabled at a time because the
-# runtime libraries get copied to root_build_dir and would collide.
-if (current_cpu == "x86") {
- msvc_toolchain("x86") {
- environment = "environment.x86"
- current_cpu = "x86"
- cl = "${goma_prefix}\"${vc_bin_dir}/cl.exe\""
- is_clang = false
- }
- msvc_toolchain("clang_x86") {
- environment = "environment.x86"
- current_cpu = "x86"
- prefix = rebase_path("//buildtools/win-x64/clang/bin", root_build_dir)
- cl = "${goma_prefix}$prefix/clang-cl.exe"
- is_clang = true
- }
+win_toolchains(target_cpu) {
+ toolchain_arch = target_cpu
}
-
-if (current_cpu == "x64") {
- msvc_toolchain("x64") {
- environment = "environment.x64"
- current_cpu = "x64"
- cl = "${goma_prefix}\"${vc_bin_dir}/cl.exe\""
- is_clang = false
- }
- msvc_toolchain("clang_x64") {
- environment = "environment.x64"
- current_cpu = "x64"
- prefix = rebase_path("//buildtools/win-x64/clang/bin", root_build_dir)
- cl = "${goma_prefix}$prefix/clang-cl.exe"
- is_clang = true
+if (host_cpu != target_cpu) {
+ win_toolchains(host_cpu) {
+ toolchain_arch = host_cpu
}
}
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py
index ee3d8ee..d1d4fb5 100644
--- a/build/toolchain/win/setup_toolchain.py
+++ b/build/toolchain/win/setup_toolchain.py
@@ -10,319 +10,141 @@
# win tool. The script assumes that the root build directory is the current dir
# and the files will be written to the current directory.
-from __future__ import print_function
-
-import json
+import errno
import os
import re
import subprocess
import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
-import gn_helpers
-
-SCRIPT_DIR = os.path.dirname(__file__)
def _ExtractImportantEnvironment(output_of_set):
- """Extracts environment variables required for the toolchain to run from
+ """Extracts environment variables required for the toolchain to run from
a textual dump output by the cmd.exe 'set' command."""
- envvars_to_save = (
- 'cipd_cache_dir', # needed by vpython
- 'homedrive', # needed by vpython
- 'homepath', # needed by vpython
- 'goma_.*', # TODO(scottmg): This is ugly, but needed for goma.
- 'include',
- 'lib',
- 'libpath',
- 'luci_context', # needed by vpython
- 'path',
- 'pathext',
- 'systemroot',
- 'temp',
- 'tmp',
- 'userprofile', # needed by vpython
- 'vpython_virtualenv_root' # needed by vpython
- )
- env = {}
- # This occasionally happens and leads to misleading SYSTEMROOT error messages
- # if not caught here.
- if output_of_set.count('=') == 0:
- raise Exception('Invalid output_of_set. Value is:\n%s' % output_of_set)
- for line in output_of_set.splitlines():
- for envvar in envvars_to_save:
- if re.match(envvar + '=', line.lower()):
- var, setting = line.split('=', 1)
- if envvar == 'path':
- # Our own rules and actions in Chromium rely on python being in the
- # path. Add the path to this python here so that if it's not in the
- # path when ninja is run later, python will still be found.
- setting = os.path.dirname(
- sys.executable) + os.pathsep + setting
- env[var.upper()] = setting
- break
- if sys.platform in ('win32', 'cygwin'):
- for required in ('SYSTEMROOT', 'TEMP', 'TMP'):
- if required not in env:
- raise Exception('Environment variable "%s" '
- 'required to be set to valid path' % required)
- return env
+ envvars_to_save = (
+ 'goma_.*', # TODO(scottmg): This is ugly, but needed for goma.
+ 'include',
+ 'lib',
+ 'libpath',
+ 'path',
+ 'pathext',
+ 'systemroot',
+ 'temp',
+ 'tmp',
+ )
+ env = {}
+ for line in output_of_set.splitlines():
+ for envvar in envvars_to_save:
+ if re.match(envvar + '=', line.decode().lower()):
+ var, setting = line.decode().split('=', 1)
+ if envvar == 'path':
+ # Our own rules (for running gyp-win-tool) and other actions in
+ # Chromium rely on python being in the path. Add the path to this
+ # python here so that if it's not in the path when ninja is run
+ # later, python will still be found.
+ setting = os.path.dirname(sys.executable) + os.pathsep + setting
+ env[var.upper()] = setting
+ break
+ for required in ('SYSTEMROOT', 'TEMP', 'TMP'):
+ if required not in env:
+ raise Exception('Environment variable "%s" '
+ 'required to be set to valid path' % required)
+ return env
-def _DetectVisualStudioPath():
- """Return path to the installed Visual Studio.
- """
-
- # Use the code in build/vs_toolchain.py to avoid duplicating code.
- chromium_dir = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..', '..'))
- sys.path.append(os.path.join(chromium_dir, 'build'))
- import vs_toolchain
- return vs_toolchain.DetectVisualStudioPath()
-
-
-def _LoadEnvFromBat(args):
- """Given a bat command, runs it and returns env vars set by it."""
- args = args[:]
- args.extend(('&&', 'set'))
- popen = subprocess.Popen(args,
- shell=True,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- variables, _ = popen.communicate()
- if popen.returncode != 0:
- raise Exception('"%s" failed with error %d' % (args, popen.returncode))
- return variables.decode(errors='ignore')
-
-
-def _LoadToolchainEnv(cpu, toolchain_root, sdk_dir, target_store):
- """Returns a dictionary with environment variables that must be set while
- running binaries from the toolchain (e.g. INCLUDE and PATH for cl.exe)."""
- # Check if we are running in the SDK command line environment and use
- # the setup script from the SDK if so. |cpu| should be either
- # 'x86' or 'x64' or 'arm' or 'arm64'.
- assert cpu in ('x86', 'x64', 'arm', 'arm64')
- if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', 1))) and sdk_dir:
- # Load environment from json file.
- env = os.path.normpath(os.path.join(sdk_dir,
- 'bin/SetEnv.%s.json' % cpu))
- env = json.load(open(env))['env']
- if env['VSINSTALLDIR'] == [["..", "..\\"]]:
- # Old-style paths were relative to the win_sdk\bin directory.
- json_relative_dir = os.path.join(sdk_dir, 'bin')
- else:
- # New-style paths are relative to the toolchain directory.
- json_relative_dir = toolchain_root
- for k in env:
- entries = [os.path.join(*([json_relative_dir] + e)) for e in env[k]]
- # clang-cl wants INCLUDE to be ;-separated even on non-Windows,
- # lld-link wants LIB to be ;-separated even on non-Windows. Path gets :.
- # The separator for INCLUDE here must match the one used in main() below.
- sep = os.pathsep if k == 'PATH' else ';'
- env[k] = sep.join(entries)
- # PATH is a bit of a special case, it's in addition to the current PATH.
- env['PATH'] = env['PATH'] + os.pathsep + os.environ['PATH']
- # Augment with the current env to pick up TEMP and friends.
- for k in os.environ:
- if k not in env:
- env[k] = os.environ[k]
-
- varlines = []
- for k in sorted(env.keys()):
- varlines.append('%s=%s' % (str(k), str(env[k])))
- variables = '\n'.join(varlines)
-
- # Check that the json file contained the same environment as the .cmd file.
- if sys.platform in ('win32', 'cygwin'):
- script = os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.cmd'))
- arg = '/' + cpu
- json_env = _ExtractImportantEnvironment(variables)
- cmd_env = _ExtractImportantEnvironment(
- _LoadEnvFromBat([script, arg]))
- assert _LowercaseDict(json_env) == _LowercaseDict(cmd_env)
- else:
- if 'GYP_MSVS_OVERRIDE_PATH' not in os.environ:
- os.environ['GYP_MSVS_OVERRIDE_PATH'] = _DetectVisualStudioPath()
- # We only support x64-hosted tools.
- script_path = os.path.normpath(
- os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'],
- 'VC/vcvarsall.bat'))
- if not os.path.exists(script_path):
- # vcvarsall.bat for VS 2017 fails if run after running vcvarsall.bat from
- # VS 2013 or VS 2015. Fix this by clearing the vsinstalldir environment
- # variable. Since vcvarsall.bat appends to the INCLUDE, LIB, and LIBPATH
- # environment variables we need to clear those to avoid getting double
- # entries when vcvarsall.bat has been run before gn gen. vcvarsall.bat
- # also adds to PATH, but there is no clean way of clearing that and it
- # doesn't seem to cause problems.
- if 'VSINSTALLDIR' in os.environ:
- del os.environ['VSINSTALLDIR']
- del os.environ['INCLUDE']
- del os.environ['LIB']
- del os.environ['LIBPATH']
- other_path = os.path.normpath(
- os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'],
- 'VC/Auxiliary/Build/vcvarsall.bat'))
- if not os.path.exists(other_path):
- raise Exception(
- '%s is missing - make sure VC++ tools are installed.' %
- script_path)
- script_path = other_path
- cpu_arg = "amd64"
- if (cpu != 'x64'):
- # x64 is default target CPU thus any other CPU requires a target set
- cpu_arg += '_' + cpu
- args = [
- script_path,
- cpu_arg,
- ]
- # Store target must come before any SDK version declaration
- if (target_store):
- args.append('store')
- # Explicitly specifying the SDK version to build with to avoid accidentally
- # building with a new and untested SDK. This should stay in sync with the
- # packaged toolchain in build/vs_toolchain.py.
- args.append('10.0.19041.0')
- variables = _LoadEnvFromBat(args)
- return _ExtractImportantEnvironment(variables)
+def _SetupScript(target_cpu, sdk_dir):
+ """Returns a command (with arguments) to be used to set up the
+ environment."""
+ # Check if we are running in the SDK command line environment and use
+ # the setup script from the SDK if so.
+ assert target_cpu in ('x86', 'x64', 'arm64')
+ if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', 1))) and sdk_dir:
+ return [os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.Cmd')),
+ '/' + target_cpu]
+ else:
+ # We only support x64-hosted tools.
+ # TODO(scottmg|dpranke): Non-depot_tools toolchain: need to get Visual
+ # Studio install location from registry.
+ return [os.path.normpath(os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'],
+ 'VC/Auxiliary/Build/vcvarsall.bat')),
+ 'amd64_x86' if target_cpu == 'x86' else 'amd64']
def _FormatAsEnvironmentBlock(envvar_dict):
- """Format as an 'environment block' directly suitable for CreateProcess.
+ """Format as an 'environment block' directly suitable for CreateProcess.
Briefly this is a list of key=value\0, terminated by an additional \0. See
CreateProcess documentation for more details."""
- block = ''
- nul = '\0'
- for key, value in envvar_dict.items():
- block += key + '=' + value + nul
- block += nul
- return block
+ block = ''
+ nul = '\0'
+ for key, value in envvar_dict.items():
+ block += key + '=' + value + nul
+ block += nul
+ return block
-def _LowercaseDict(d):
- """Returns a copy of `d` with both key and values lowercased.
+def _CopyTool(source_path):
+ """Copies the given tool to the current directory, including a warning not
+ to edit it."""
+ with open(source_path) as source_file:
+ tool_source = source_file.readlines()
- Args:
- d: dict to lowercase (e.g. {'A': 'BcD'}).
-
- Returns:
- A dict with both keys and values lowercased (e.g.: {'a': 'bcd'}).
- """
- return {k.lower(): d[k].lower() for k in d}
-
-
-def FindFileInEnvList(env, env_name, separator, file_name, optional=False):
- parts = env[env_name].split(separator)
- for path in parts:
- if os.path.exists(os.path.join(path, file_name)):
- return os.path.realpath(path)
- assert optional, "%s is not found in %s:\n%s\nCheck if it is installed." % (
- file_name, env_name, '\n'.join(parts))
- return ''
+ # Add header and write it out to the current directory (which should be the
+ # root build dir).
+ with open("gyp-win-tool", 'w') as tool_file:
+ tool_file.write(''.join([tool_source[0],
+ '# Generated by setup_toolchain.py do not edit.\n']
+ + tool_source[1:]))
def main():
- if len(sys.argv) != 7:
- print('Usage setup_toolchain.py '
- '<visual studio path> <win sdk path> '
- '<runtime dirs> <target_os> <target_cpu> '
- '<environment block name|none>')
- sys.exit(2)
- # toolchain_root and win_sdk_path are only read if the hermetic Windows
- # toolchain is set, that is if DEPOT_TOOLS_WIN_TOOLCHAIN is not set to 0.
- # With the hermetic Windows toolchain, the visual studio path in argv[1]
- # is the root of the Windows toolchain directory.
- toolchain_root = sys.argv[1]
- win_sdk_path = sys.argv[2]
+ if len(sys.argv) != 5:
+ print('Usage setup_toolchain.py '
+ '<visual studio path> <win sdk path> '
+ '<runtime dirs> <target_cpu>')
+ sys.exit(2)
+ win_sdk_path = sys.argv[2]
+ runtime_dirs = sys.argv[3]
+ target_cpu = sys.argv[4]
- runtime_dirs = sys.argv[3]
- target_os = sys.argv[4]
- target_cpu = sys.argv[5]
- environment_block_name = sys.argv[6]
- if (environment_block_name == 'none'):
- environment_block_name = ''
+ cpus = ('x86', 'x64', 'arm64')
+ assert target_cpu in cpus
+ vc_bin_dir = ''
- if (target_os == 'winuwp'):
- target_store = True
- else:
- target_store = False
+ # TODO(scottmg|goma): Do we need an equivalent of
+ # ninja_use_custom_environment_files?
- cpus = ('x86', 'x64', 'arm', 'arm64')
- assert target_cpu in cpus
- vc_bin_dir = ''
- vc_lib_path = ''
- vc_lib_atlmfc_path = ''
- vc_lib_um_path = ''
- include = ''
- lib = ''
+ for cpu in cpus:
+ # Extract environment variables for subprocesses.
+ args = _SetupScript(cpu, win_sdk_path)
+ args.extend(('&&', 'set'))
+ popen = subprocess.Popen(
+ args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ variables, _ = popen.communicate()
+ env = _ExtractImportantEnvironment(variables)
+ env['PATH'] = runtime_dirs + ';' + env['PATH']
- # TODO(scottmg|goma): Do we need an equivalent of
- # ninja_use_custom_environment_files?
+ if cpu == target_cpu:
+ for path in env['PATH'].split(os.pathsep):
+ if os.path.exists(os.path.join(path, 'cl.exe')):
+ vc_bin_dir = os.path.realpath(path)
+ break
- def relflag(
- s): # Make s relative to builddir when cwd and sdk on same drive.
- try:
- return os.path.relpath(s)
- except ValueError:
- return s
+ # The Windows SDK include directories must be first. They both have a sal.h,
+ # and the SDK one is newer and the SDK uses some newer features from it not
+ # present in the Visual Studio one.
- def q(s): # Quote s if it contains spaces or other weird characters.
- return s if re.match(r'^[a-zA-Z0-9._/\\:-]*$', s) else '"' + s + '"'
+ if win_sdk_path:
+ additional_includes = ('{sdk_dir}\\Include\\shared;' +
+ '{sdk_dir}\\Include\\um;' +
+ '{sdk_dir}\\Include\\winrt;').format(
+ sdk_dir=win_sdk_path)
+ env['INCLUDE'] = additional_includes + env['INCLUDE']
+ env_block = _FormatAsEnvironmentBlock(env)
+ with open('environment.' + cpu, 'wb') as f:
+ f.write(env_block.encode())
- for cpu in cpus:
- if cpu == target_cpu:
- # Extract environment variables for subprocesses.
- env = _LoadToolchainEnv(cpu, toolchain_root, win_sdk_path,
- target_store)
- env['PATH'] = runtime_dirs + os.pathsep + env['PATH']
-
- vc_bin_dir = FindFileInEnvList(env, 'PATH', os.pathsep, 'cl.exe')
- vc_lib_path = FindFileInEnvList(env, 'LIB', ';', 'msvcrt.lib')
- vc_lib_atlmfc_path = FindFileInEnvList(env,
- 'LIB',
- ';',
- 'atls.lib',
- optional=True)
- vc_lib_um_path = FindFileInEnvList(env, 'LIB', ';', 'user32.lib')
-
- # The separator for INCLUDE here must match the one used in
- # _LoadToolchainEnv() above.
- include = [
- p.replace('"', r'\"') for p in env['INCLUDE'].split(';') if p
- ]
- include = list(map(relflag, include))
-
- lib = [p.replace('"', r'\"') for p in env['LIB'].split(';') if p]
- lib = list(map(relflag, lib))
-
- include_I = ' '.join([q('/I' + i) for i in include])
- include_imsvc = ' '.join([q('-imsvc' + i) for i in include])
- libpath_flags = ' '.join([q('-libpath:' + i) for i in lib])
-
- if (environment_block_name != ''):
- env_block = _FormatAsEnvironmentBlock(env)
- with open(environment_block_name, 'w') as f:
- f.write(env_block)
-
- print('vc_bin_dir = ' + gn_helpers.ToGNString(vc_bin_dir))
- assert include_I
- print('include_flags_I = ' + gn_helpers.ToGNString(include_I))
- assert include_imsvc
- if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN',
- 1))) and win_sdk_path:
- print('include_flags_imsvc = ' +
- gn_helpers.ToGNString(q('/winsysroot' + relflag(toolchain_root))))
- else:
- print('include_flags_imsvc = ' + gn_helpers.ToGNString(include_imsvc))
- print('vc_lib_path = ' + gn_helpers.ToGNString(vc_lib_path))
- # Possible atlmfc library path gets introduced in the future for store thus
- # output result if a result exists.
- if (vc_lib_atlmfc_path != ''):
- print('vc_lib_atlmfc_path = ' +
- gn_helpers.ToGNString(vc_lib_atlmfc_path))
- print('vc_lib_um_path = ' + gn_helpers.ToGNString(vc_lib_um_path))
- print('paths = ' + gn_helpers.ToGNString(env['PATH']))
- assert libpath_flags
- print('libpath_flags = ' + gn_helpers.ToGNString(libpath_flags))
+ assert vc_bin_dir
+ print('vc_bin_dir = "%s"' % vc_bin_dir)
if __name__ == '__main__':
- main()
+ main()
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index 5ac59ba..6314e5e 100644
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -1,17 +1,18 @@
#!/usr/bin/env python3
+#
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# For Dart developers:
+# For Dart/Flutter developers:
# This file keeps the MSVC toolchain up-to-date for Google developers.
# It is copied from Chromium:
# https://cs.chromium.org/chromium/src/build/vs_toolchain.py
-# with modifications that update paths and remove dependencies on gyp.
+# with modifications that update paths, and remove dependencies on gyp.
# To update to a new MSVC toolchain, copy the updated script from the Chromium
-# tree, edit to make it work in the Dart tree by updating paths in the original script.
+# tree, and edit to make it work in the Dart tree by updating paths in the original script.
-from __future__ import print_function
+
import collections
import glob
@@ -25,49 +26,24 @@
import subprocess
import sys
+
from gn_helpers import ToGNString
-# VS 2019 16.61 with 10.0.19041 SDK, and 10.0.17134 version of
-# d3dcompiler_47.dll, with ARM64 libraries and UWP support.
-# See go/chromium-msvc-toolchain for instructions about how to update the
-# toolchain.
-#
-# When updating the toolchain, consider the following areas impacted by the
-# toolchain version:
-#
-# * //base/win/windows_version.cc NTDDI preprocessor check
-# Triggers a compiler error if the available SDK is older than the minimum.
-# * //build/config/win/BUILD.gn NTDDI_VERSION value
-# Affects the availability of APIs in the toolchain headers.
-# * //docs/windows_build_instructions.md mentions of VS or Windows SDK.
-# Keeps the document consistent with the toolchain version.
-TOOLCHAIN_HASH = '20d5f2553f'
-
script_dir = os.path.dirname(os.path.realpath(__file__))
-dart_src = os.path.abspath(os.path.join(script_dir, os.pardir))
-sys.path.insert(0, os.path.join(dart_src, 'tools'))
json_data_file = os.path.join(script_dir, 'win_toolchain.json')
+sys.path.insert(0, os.path.join(script_dir, '..', 'tools'))
+
# VS versions are listed in descending order of priority (highest first).
MSVS_VERSIONS = collections.OrderedDict([
- ('2019', '16.0'),
- ('2017', '15.0'),
+ ('2017', '15.0'),
+ ('2019', '16.0'),
+ ('2022', '17.0'),
])
-# List of preferred VC toolset version based on MSVS
-MSVC_TOOLSET_VERSION = {
- '2019': 'VC142',
- '2017': 'VC141',
-}
-
-
-def _HostIsWindows():
- """Returns True if running on a Windows host (including under cygwin)."""
- return sys.platform in ('win32', 'cygwin')
-
def SetEnvironmentAndGetRuntimeDllDirs():
- """Sets up os.environ to use the depot_tools VS toolchain with gyp, and
+ """Sets up os.environ to use the depot_tools VS toolchain with gyp, and
returns the location of the VC runtime DLLs so they can be copied into
the output directory after gyp generation.
@@ -75,70 +51,73 @@
generated separately because there are multiple folders for the arm64 VC
runtime.
"""
- vs_runtime_dll_dirs = None
- depot_tools_win_toolchain = \
- bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
- # When running on a non-Windows host, only do this if the SDK has explicitly
- # been downloaded before (in which case json_data_file will exist).
- if ((_HostIsWindows() or os.path.exists(json_data_file)) and
- depot_tools_win_toolchain):
- if ShouldUpdateToolchain():
- if len(sys.argv) > 1 and sys.argv[1] == 'update':
- update_result = Update()
- else:
- update_result = Update(no_download=True)
- if update_result != 0:
- raise Exception('Failed to update, error code %d.' %
- update_result)
- with open(json_data_file, 'r') as tempf:
- toolchain_data = json.load(tempf)
+ vs_runtime_dll_dirs = None
+ depot_tools_win_toolchain = \
+ bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
+ # When running on a non-Windows host, only do this if the SDK has explicitly
+ # been downloaded before (in which case json_data_file will exist).
+ if ((sys.platform in ('win32', 'cygwin') or os.path.exists(json_data_file))
+ and depot_tools_win_toolchain):
+ if ShouldUpdateToolchain():
+ if len(sys.argv) > 1 and sys.argv[1] == 'update':
+ update_result = Update()
+ else:
+ update_result = Update(no_download=True)
+ if update_result != 0:
+ raise Exception('Failed to update, error code %d.' % update_result)
+ with open(json_data_file, 'r') as tempf:
+ toolchain_data = json.load(tempf)
- toolchain = toolchain_data['path']
- version = toolchain_data['version']
- win_sdk = toolchain_data.get('win_sdk')
- wdk = toolchain_data['wdk']
- # TODO(scottmg): The order unfortunately matters in these. They should be
- # split into separate keys for x64/x86/arm64. (See CopyDlls call below).
- # http://crbug.com/345992
- vs_runtime_dll_dirs = toolchain_data['runtime_dirs']
- # The number of runtime_dirs in the toolchain_data was two (x64/x86) but
- # changed to three (x64/x86/arm64) and this code needs to handle both
- # possibilities, which can change independently from this code.
- if len(vs_runtime_dll_dirs) == 2:
- vs_runtime_dll_dirs.append('Arm64Unused')
+ toolchain = toolchain_data['path']
+ version = toolchain_data['version']
+ win_sdk = toolchain_data.get('win_sdk')
+ if not win_sdk:
+ win_sdk = toolchain_data['win8sdk']
+ wdk = toolchain_data['wdk']
+ # TODO(scottmg): The order unfortunately matters in these. They should be
+ # split into separate keys for x64/x86/arm64. (See CopyDlls call below).
+ # http://crbug.com/345992
+ vs_runtime_dll_dirs = toolchain_data['runtime_dirs']
+ # The number of runtime_dirs in the toolchain_data was two (x64/x86) but
+ # changed to three (x64/x86/arm64) and this code needs to handle both
+ # possibilities, which can change independently from this code.
+ if len(vs_runtime_dll_dirs) == 2:
+ vs_runtime_dll_dirs.append('Arm64Unused')
- os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
+ os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
+ os.environ['GYP_MSVS_VERSION'] = version
- os.environ['WINDOWSSDKDIR'] = win_sdk
- os.environ['WDK_DIR'] = wdk
- # Include the VS runtime in the PATH in case it's not machine-installed.
- runtime_path = os.path.pathsep.join(vs_runtime_dll_dirs)
- os.environ['PATH'] = runtime_path + os.path.pathsep + os.environ['PATH']
- elif sys.platform == 'win32' and not depot_tools_win_toolchain:
- if not 'GYP_MSVS_OVERRIDE_PATH' in os.environ:
- os.environ['GYP_MSVS_OVERRIDE_PATH'] = DetectVisualStudioPath()
+ os.environ['WINDOWSSDKDIR'] = win_sdk
+ os.environ['WDK_DIR'] = wdk
+ # Include the VS runtime in the PATH in case it's not machine-installed.
+ runtime_path = os.path.pathsep.join(vs_runtime_dll_dirs)
+ os.environ['PATH'] = runtime_path + os.path.pathsep + os.environ['PATH']
+ elif sys.platform == 'win32' and not depot_tools_win_toolchain:
+ if not 'GYP_MSVS_OVERRIDE_PATH' in os.environ:
+ os.environ['GYP_MSVS_OVERRIDE_PATH'] = DetectVisualStudioPath()
+ if not 'GYP_MSVS_VERSION' in os.environ:
+ os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion()
- # When using an installed toolchain these files aren't needed in the output
- # directory in order to run binaries locally, but they are needed in order
- # to create isolates or the mini_installer. Copying them to the output
- # directory ensures that they are available when needed.
- bitness = platform.architecture()[0]
- # When running 64-bit python the x64 DLLs will be in System32
- # ARM64 binaries will not be available in the system directories because we
- # don't build on ARM64 machines.
- x64_path = 'System32' if bitness == '64bit' else 'Sysnative'
- x64_path = os.path.join(os.path.expandvars('%windir%'), x64_path)
- vs_runtime_dll_dirs = [
- x64_path,
- os.path.join(os.path.expandvars('%windir%'), 'SysWOW64'),
- 'Arm64Unused'
- ]
+ # When using an installed toolchain these files aren't needed in the output
+ # directory in order to run binaries locally, but they are needed in order
+ # to create isolates or the mini_installer. Copying them to the output
+ # directory ensures that they are available when needed.
+ bitness = platform.architecture()[0]
+ # When running 64-bit python the x64 DLLs will be in System32
+ # ARM64 binaries will not be available in the system directories because we
+ # don't build on ARM64 machines.
+ x64_path = 'System32' if bitness == '64bit' else 'Sysnative'
+ x64_path = os.path.join(os.path.expandvars('%windir%'), x64_path)
+ vs_runtime_dll_dirs = [x64_path,
+ os.path.join(os.path.expandvars('%windir%'),
+ 'SysWOW64'),
+ 'Arm64Unused']
- return vs_runtime_dll_dirs
+ return vs_runtime_dll_dirs
def _RegistryGetValueUsingWinReg(key, value):
- """Use the _winreg module to obtain the value of a registry key.
+ """Use the _winreg module to obtain the value of a registry key.
Args:
key: The registry key.
@@ -147,249 +126,228 @@
contents of the registry key's value, or None on failure. Throws
ImportError if _winreg is unavailable.
"""
- import _winreg
- try:
- root, subkey = key.split('\\', 1)
- assert root == 'HKLM' # Only need HKLM for now.
- with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, subkey) as hkey:
- return _winreg.QueryValueEx(hkey, value)[0]
- except WindowsError:
- return None
+ import winreg
+ try:
+ root, subkey = key.split('\\', 1)
+ assert root == 'HKLM' # Only need HKLM for now.
+ with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, subkey) as hkey:
+ return winreg.QueryValueEx(hkey, value)[0]
+ except WindowsError:
+ return None
def _RegistryGetValue(key, value):
- try:
- return _RegistryGetValueUsingWinReg(key, value)
- except ImportError:
- raise Exception('The python library _winreg not found.')
+ try:
+ return _RegistryGetValueUsingWinReg(key, value)
+ except ImportError:
+ raise Exception('The python library _winreg not found.')
def GetVisualStudioVersion():
- """Return best available version of Visual Studio.
+ """Return best available version of Visual Studio.
"""
- supported_versions = list(MSVS_VERSIONS.keys())
- # VS installed in depot_tools for Googlers
- if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1'))):
- return supported_versions[0]
+ env_version = os.environ.get('GYP_MSVS_VERSION')
+ if env_version:
+ return env_version
- # VS installed in system for external developers
- supported_versions_str = ', '.join(
- '{} ({})'.format(v, k) for k, v in MSVS_VERSIONS.items())
- available_versions = []
- for version in supported_versions:
- # Checking vs%s_install environment variables.
- # For example, vs2019_install could have the value
- # "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community".
- # Only vs2017_install and vs2019_install are supported.
- path = os.environ.get('vs%s_install' % version)
- if path and os.path.exists(path):
- available_versions.append(version)
- break
- # Detecting VS under possible paths.
- path = os.path.expandvars('%ProgramFiles(x86)%' +
- '/Microsoft Visual Studio/%s' % version)
- if path and any(
- os.path.exists(os.path.join(path, edition))
- for edition in ('Enterprise', 'Professional', 'Community',
- 'Preview', 'BuildTools')):
- available_versions.append(version)
- break
+ supported_versions = list(MSVS_VERSIONS.keys())
- if not available_versions:
- raise Exception('No supported Visual Studio can be found.'
- ' Supported versions are: %s.' % supported_versions_str)
- return available_versions[0]
+ # VS installed in depot_tools for Googlers
+ if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1'))):
+ return list(supported_versions)[0]
+
+ # VS installed in system for external developers
+ supported_versions_str = ', '.join('{} ({})'.format(v,k)
+ for k,v in list(MSVS_VERSIONS.items()))
+ available_versions = []
+ for version in supported_versions:
+ for path in (
+ os.environ.get('vs%s_install' % version),
+ os.path.expandvars('%ProgramFiles(x86)%' +
+ '/Microsoft Visual Studio/%s' % version),
+ os.path.expandvars('%ProgramFiles%' +
+ '/Microsoft Visual Studio/%s' % version)):
+ if path and os.path.exists(path):
+ available_versions.append(version)
+ break
+
+ if not available_versions:
+ raise Exception('No supported Visual Studio can be found.'
+ ' Supported versions are: %s.' % supported_versions_str)
+ return available_versions[0]
def DetectVisualStudioPath():
- """Return path to the installed Visual Studio.
+ """Return path to the GYP_MSVS_VERSION of Visual Studio.
"""
- # Note that this code is used from
- # build/toolchain/win/setup_toolchain.py as well.
- version_as_year = GetVisualStudioVersion()
+ # Note that this code is used from
+ # build/toolchain/win/setup_toolchain.py as well.
+ version_as_year = GetVisualStudioVersion()
- # The VC++ >=2017 install location needs to be located using COM instead of
- # the registry. For details see:
- # https://blogs.msdn.microsoft.com/heaths/2016/09/15/changes-to-visual-studio-15-setup/
- # For now we use a hardcoded default with an environment variable override.
- for path in (os.environ.get('vs%s_install' % version_as_year),
- os.path.expandvars('%ProgramFiles(x86)%' +
- '/Microsoft Visual Studio/%s/Enterprise' %
- version_as_year),
- os.path.expandvars('%ProgramFiles(x86)%' +
- '/Microsoft Visual Studio/%s/Professional' %
- version_as_year),
- os.path.expandvars('%ProgramFiles(x86)%' +
- '/Microsoft Visual Studio/%s/Community' %
- version_as_year),
- os.path.expandvars('%ProgramFiles(x86)%' +
- '/Microsoft Visual Studio/%s/Preview' %
- version_as_year),
- os.path.expandvars('%ProgramFiles(x86)%' +
- '/Microsoft Visual Studio/%s/BuildTools' %
- version_as_year)):
- if path and os.path.exists(path):
- return path
+ # The VC++ >=2017 install location needs to be located using COM instead of
+ # the registry. For details see:
+ # https://blogs.msdn.microsoft.com/heaths/2016/09/15/changes-to-visual-studio-15-setup/
+ # For now we use a hardcoded default with an environment variable override.
+ possible_install_paths = (
+ os.path.expandvars('%s/Microsoft Visual Studio/%s/%s' %
+ (program_path_var, version_as_year, product))
+ for program_path_var in ('%ProgramFiles%', '%ProgramFiles(x86)%')
+ for product in ('Enterprise', 'Professional', 'Community', 'Preview'))
+ for path in (
+ os.environ.get('vs%s_install' % version_as_year), *possible_install_paths):
+ if path and os.path.exists(path):
+ return path
- raise Exception('Visual Studio Version %s not found.' % version_as_year)
+ raise Exception('Visual Studio Version %s (from GYP_MSVS_VERSION)'
+ ' not found.' % version_as_year)
def _CopyRuntimeImpl(target, source, verbose=True):
- """Copy |source| to |target| if it doesn't already exist or if it needs to be
+ """Copy |source| to |target| if it doesn't already exist or if it needs to be
updated (comparing last modified time as an approximate float match as for
some reason the values tend to differ by ~1e-07 despite being copies of the
same file... https://crbug.com/603603).
"""
- if (os.path.isdir(os.path.dirname(target)) and
- (not os.path.isfile(target) or
- abs(os.stat(target).st_mtime - os.stat(source).st_mtime) >= 0.01)):
- if verbose:
- print('Copying %s to %s...' % (source, target))
- if os.path.exists(target):
- # Make the file writable so that we can delete it now, and keep it
- # readable.
- os.chmod(target, stat.S_IWRITE | stat.S_IREAD)
- os.unlink(target)
- shutil.copy2(source, target)
- # Make the file writable so that we can overwrite or delete it later,
- # keep it readable.
- os.chmod(target, stat.S_IWRITE | stat.S_IREAD)
-
+ if (os.path.isdir(os.path.dirname(target)) and
+ (not os.path.isfile(target) or
+ abs(os.stat(target).st_mtime - os.stat(source).st_mtime) >= 0.01)):
+ if verbose:
+ print('Copying %s to %s...' % (source, target))
+ if os.path.exists(target):
+ # Make the file writable so that we can delete it now, and keep it
+ # readable.
+ os.chmod(target, stat.S_IWRITE | stat.S_IREAD)
+ os.unlink(target)
+ shutil.copy2(source, target)
+ # Make the file writable so that we can overwrite or delete it later,
+ # keep it readable.
+ os.chmod(target, stat.S_IWRITE | stat.S_IREAD)
def _SortByHighestVersionNumberFirst(list_of_str_versions):
- """This sorts |list_of_str_versions| according to version number rules
+ """This sorts |list_of_str_versions| according to version number rules
so that version "1.12" is higher than version "1.9". Does not work
with non-numeric versions like 1.4.a8 which will be higher than
1.4.a12. It does handle the versions being embedded in file paths.
"""
+ def to_int_if_int(x):
+ try:
+ return int(x)
+ except ValueError:
+ return x
- def to_int_if_int(x):
- try:
- return int(x)
- except ValueError:
- return x
+ def to_number_sequence(x):
+ part_sequence = re.split(r'[\\/\.]', x)
+ return [to_int_if_int(x) for x in part_sequence]
- def to_number_sequence(x):
- part_sequence = re.split(r'[\\/\.]', x)
- return [to_int_if_int(x) for x in part_sequence]
+ list_of_str_versions.sort(key=to_number_sequence, reverse=True)
- list_of_str_versions.sort(key=to_number_sequence, reverse=True)
-
-
-def _CopyUCRTRuntime(target_dir, source_dir, target_cpu, suffix):
- """Copy both the msvcp and vccorlib runtime DLLs, only if the target doesn't
+def _CopyUCRTRuntime(target_dir, source_dir, target_cpu, dll_pattern, suffix):
+ """Copy both the msvcp and vccorlib runtime DLLs, only if the target doesn't
exist, but the target directory does exist."""
- if target_cpu == 'arm64':
- # Windows ARM64 VCRuntime is located at {toolchain_root}/VC/Redist/MSVC/
- # {x.y.z}/[debug_nonredist/]arm64/Microsoft.VC14x.CRT/.
- # Select VC toolset directory based on Visual Studio version
- vc_redist_root = FindVCRedistRoot()
- if suffix.startswith('.'):
- vc_toolset_dir = 'Microsoft.{}.CRT' \
- .format(MSVC_TOOLSET_VERSION[GetVisualStudioVersion()])
- source_dir = os.path.join(vc_redist_root, 'arm64', vc_toolset_dir)
- else:
- vc_toolset_dir = 'Microsoft.{}.DebugCRT' \
- .format(MSVC_TOOLSET_VERSION[GetVisualStudioVersion()])
- source_dir = os.path.join(vc_redist_root, 'debug_nonredist',
- 'arm64', vc_toolset_dir)
- file_parts = ('msvcp140', 'vccorlib140', 'vcruntime140')
- if target_cpu == 'x64' and GetVisualStudioVersion() != '2017':
- file_parts = file_parts + ('vcruntime140_1',)
- for file_part in file_parts:
- dll = file_part + suffix
- target = os.path.join(target_dir, dll)
- source = os.path.join(source_dir, dll)
- _CopyRuntimeImpl(target, source)
- # Copy the UCRT files from the Windows SDK. This location includes the
- # api-ms-win-crt-*.dll files that are not found in the Windows directory.
- # These files are needed for component builds. If WINDOWSSDKDIR is not set
- # use the default SDK path. This will be the case when
- # DEPOT_TOOLS_WIN_TOOLCHAIN=0 and vcvarsall.bat has not been run.
- win_sdk_dir = os.path.normpath(
- os.environ.get(
- 'WINDOWSSDKDIR',
- os.path.expandvars('%ProgramFiles(x86)%'
- '\\Windows Kits\\10')))
- # ARM64 doesn't have a redist for the ucrt DLLs because they are always
- # present in the OS.
- if target_cpu != 'arm64':
- # Starting with the 10.0.17763 SDK the ucrt files are in a version-named
- # directory - this handles both cases.
- redist_dir = os.path.join(win_sdk_dir, 'Redist')
- version_dirs = glob.glob(os.path.join(redist_dir, '10.*'))
- if len(version_dirs) > 0:
- _SortByHighestVersionNumberFirst(version_dirs)
- redist_dir = version_dirs[0]
- ucrt_dll_dirs = os.path.join(redist_dir, 'ucrt', 'DLLs', target_cpu)
- ucrt_files = glob.glob(os.path.join(ucrt_dll_dirs, 'api-ms-win-*.dll'))
- assert len(ucrt_files) > 0
- for ucrt_src_file in ucrt_files:
- file_part = os.path.basename(ucrt_src_file)
- ucrt_dst_file = os.path.join(target_dir, file_part)
- _CopyRuntimeImpl(ucrt_dst_file, ucrt_src_file, False)
- # We must copy ucrtbase.dll for x64/x86, and ucrtbased.dll for all CPU types.
- if target_cpu != 'arm64' or not suffix.startswith('.'):
- if not suffix.startswith('.'):
- # ucrtbased.dll is located at {win_sdk_dir}/bin/{a.b.c.d}/{target_cpu}/
- # ucrt/.
- sdk_bin_root = os.path.join(win_sdk_dir, 'bin')
- sdk_bin_sub_dirs = glob.glob(os.path.join(sdk_bin_root, '10.*'))
- # Select the most recent SDK if there are multiple versions installed.
- _SortByHighestVersionNumberFirst(sdk_bin_sub_dirs)
- for directory in sdk_bin_sub_dirs:
- sdk_redist_root_version = os.path.join(sdk_bin_root, directory)
- if not os.path.isdir(sdk_redist_root_version):
- continue
- source_dir = os.path.join(sdk_redist_root_version, target_cpu,
- 'ucrt')
- break
- _CopyRuntimeImpl(os.path.join(target_dir, 'ucrtbase' + suffix),
- os.path.join(source_dir, 'ucrtbase' + suffix))
+ if target_cpu == 'arm64':
+ # Windows ARM64 VCRuntime is located at {toolchain_root}/VC/Redist/MSVC/
+ # {x.y.z}/[debug_nonredist/]arm64/Microsoft.VC141.CRT/.
+ vc_redist_root = FindVCRedistRoot()
+ if suffix.startswith('.'):
+ source_dir = os.path.join(vc_redist_root,
+ 'arm64', 'Microsoft.VC141.CRT')
+ else:
+ source_dir = os.path.join(vc_redist_root, 'debug_nonredist',
+ 'arm64', 'Microsoft.VC141.DebugCRT')
+ for file_part in ('msvcp', 'vccorlib', 'vcruntime'):
+ dll = dll_pattern % file_part
+ target = os.path.join(target_dir, dll)
+ source = os.path.join(source_dir, dll)
+ _CopyRuntimeImpl(target, source)
+ # Copy the UCRT files from the Windows SDK. This location includes the
+ # api-ms-win-crt-*.dll files that are not found in the Windows directory.
+ # These files are needed for component builds. If WINDOWSSDKDIR is not set
+ # use the default SDK path. This will be the case when
+ # DEPOT_TOOLS_WIN_TOOLCHAIN=0 and vcvarsall.bat has not been run.
+ win_sdk_dir = os.path.normpath(
+ os.environ.get('WINDOWSSDKDIR',
+ os.path.expandvars('%ProgramFiles(x86)%'
+ '\\Windows Kits\\10')))
+ # ARM64 doesn't have a redist for the ucrt DLLs because they are always
+ # present in the OS.
+ if target_cpu != 'arm64':
+ # Starting with the 10.0.17763 SDK the ucrt files are in a version-named
+ # directory - this handles both cases.
+ redist_dir = os.path.join(win_sdk_dir, 'Redist')
+ version_dirs = glob.glob(os.path.join(redist_dir, '10.*'))
+ if len(version_dirs) > 0:
+ _SortByHighestVersionNumberFirst(version_dirs)
+ redist_dir = version_dirs[0]
+ ucrt_dll_dirs = os.path.join(redist_dir, 'ucrt', 'DLLs', target_cpu)
+ ucrt_files = glob.glob(os.path.join(ucrt_dll_dirs, 'api-ms-win-*.dll'))
+ assert len(ucrt_files) > 0
+ for ucrt_src_file in ucrt_files:
+ file_part = os.path.basename(ucrt_src_file)
+ ucrt_dst_file = os.path.join(target_dir, file_part)
+ _CopyRuntimeImpl(ucrt_dst_file, ucrt_src_file, False)
+ # We must copy ucrtbase.dll for x64/x86, and ucrtbased.dll for all CPU types.
+ if target_cpu != 'arm64' or not suffix.startswith('.'):
+ if not suffix.startswith('.'):
+ # ucrtbased.dll is located at {win_sdk_dir}/bin/{a.b.c.d}/{target_cpu}/
+ # ucrt/.
+ sdk_bin_root = os.path.join(win_sdk_dir, 'bin')
+ sdk_bin_sub_dirs = glob.glob(os.path.join(sdk_bin_root, '10.*'))
+ # Select the most recent SDK if there are multiple versions installed.
+ _SortByHighestVersionNumberFirst(sdk_bin_sub_dirs)
+ for directory in sdk_bin_sub_dirs:
+ sdk_redist_root_version = os.path.join(sdk_bin_root, directory)
+ if not os.path.isdir(sdk_redist_root_version):
+ continue
+ source_dir = os.path.join(sdk_redist_root_version, target_cpu, 'ucrt')
+ break
+ _CopyRuntimeImpl(os.path.join(target_dir, 'ucrtbase' + suffix),
+ os.path.join(source_dir, 'ucrtbase' + suffix))
def FindVCComponentRoot(component):
- """Find the most recent Tools or Redist or other directory in an MSVC install.
+ """Find the most recent Tools or Redist or other directory in an MSVC install.
Typical results are {toolchain_root}/VC/{component}/MSVC/{x.y.z}. The {x.y.z}
version number part changes frequently so the highest version number found is
used.
"""
- SetEnvironmentAndGetRuntimeDllDirs()
- assert ('GYP_MSVS_OVERRIDE_PATH' in os.environ)
- vc_component_msvc_root = os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'],
- 'VC', component, 'MSVC')
- vc_component_msvc_contents = glob.glob(
- os.path.join(vc_component_msvc_root, '14.*'))
- # Select the most recent toolchain if there are several.
- _SortByHighestVersionNumberFirst(vc_component_msvc_contents)
- for directory in vc_component_msvc_contents:
- if os.path.isdir(directory):
- return directory
- raise Exception('Unable to find the VC %s directory.' % component)
+ SetEnvironmentAndGetRuntimeDllDirs()
+ assert ('GYP_MSVS_OVERRIDE_PATH' in os.environ)
+ vc_component_msvc_root = os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'],
+ 'VC', component, 'MSVC')
+ vc_component_msvc_contents = os.listdir(vc_component_msvc_root)
+ # Select the most recent toolchain if there are several.
+ _SortByHighestVersionNumberFirst(vc_component_msvc_contents)
+ for directory in vc_component_msvc_contents:
+ if not os.path.isdir(os.path.join(vc_component_msvc_root, directory)):
+ continue
+ if re.match(r'14\.\d+\.\d+', directory):
+ return os.path.join(vc_component_msvc_root, directory)
+ raise Exception('Unable to find the VC %s directory.' % component)
def FindVCRedistRoot():
- """In >=VS2017, Redist binaries are located in
+ """In >=VS2017, Redist binaries are located in
{toolchain_root}/VC/Redist/MSVC/{x.y.z}/{target_cpu}/.
This returns the '{toolchain_root}/VC/Redist/MSVC/{x.y.z}/' path.
"""
- return FindVCComponentRoot('Redist')
+ return FindVCComponentRoot('Redist')
def _CopyRuntime(target_dir, source_dir, target_cpu, debug):
- """Copy the VS runtime DLLs, only if the target doesn't exist, but the target
+ """Copy the VS runtime DLLs, only if the target doesn't exist, but the target
directory does exist. Handles VS 2015, 2017 and 2019."""
- suffix = 'd.dll' if debug else '.dll'
- # VS 2015, 2017 and 2019 use the same CRT DLLs.
- _CopyUCRTRuntime(target_dir, source_dir, target_cpu, suffix)
+ suffix = 'd.dll' if debug else '.dll'
+ # VS 2015, 2017 and 2019 use the same CRT DLLs.
+ _CopyUCRTRuntime(target_dir, source_dir, target_cpu, '%s140' + suffix,
+ suffix)
def CopyDlls(target_dir, configuration, target_cpu):
- """Copy the VS runtime DLLs into the requested directory as needed.
+ """Copy the VS runtime DLLs into the requested directory as needed.
configuration is one of 'Debug' or 'Release'.
target_cpu is one of 'x86', 'x64' or 'arm64'.
@@ -397,27 +355,27 @@
The debug configuration gets both the debug and release DLLs; the
release config only the latter.
"""
- vs_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
- if not vs_runtime_dll_dirs:
- return
+ vs_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
+ if not vs_runtime_dll_dirs:
+ return
- x64_runtime, x86_runtime, arm64_runtime = vs_runtime_dll_dirs
- if target_cpu == 'x64':
- runtime_dir = x64_runtime
- elif target_cpu == 'x86':
- runtime_dir = x86_runtime
- elif target_cpu == 'arm64':
- runtime_dir = arm64_runtime
- else:
- raise Exception('Unknown target_cpu: ' + target_cpu)
- _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=False)
- if configuration == 'Debug':
- _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=True)
- _CopyDebugger(target_dir, target_cpu)
+ x64_runtime, x86_runtime, arm64_runtime = vs_runtime_dll_dirs
+ if target_cpu == 'x64':
+ runtime_dir = x64_runtime
+ elif target_cpu == 'x86':
+ runtime_dir = x86_runtime
+ elif target_cpu == 'arm64':
+ runtime_dir = arm64_runtime
+ else:
+ raise Exception('Unknown target_cpu: ' + target_cpu)
+ _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=False)
+ if configuration == 'Debug':
+ _CopyRuntime(target_dir, runtime_dir, target_cpu, debug=True)
+ _CopyDebugger(target_dir, target_cpu)
def _CopyDebugger(target_dir, target_cpu):
- """Copy dbghelp.dll and dbgcore.dll into the requested directory as needed.
+ """Copy dbghelp.dll and dbgcore.dll into the requested directory as needed.
target_cpu is one of 'x86', 'x64' or 'arm64'.
@@ -429,150 +387,148 @@
dbgcore.dll is needed when using some functions from dbghelp.dll (like
MinidumpWriteDump).
"""
- win_sdk_dir = SetEnvironmentAndGetSDKDir()
- if not win_sdk_dir:
- return
+ win_sdk_dir = SetEnvironmentAndGetSDKDir()
+ if not win_sdk_dir:
+ return
- # List of debug files that should be copied, the first element of the tuple is
- # the name of the file and the second indicates if it's optional.
- debug_files = [('dbghelp.dll', False), ('dbgcore.dll', True)]
- # The UCRT is not a redistributable component on arm64.
- if target_cpu != 'arm64':
- debug_files.extend([('api-ms-win-downlevel-kernel32-l2-1-0.dll', False),
- ('api-ms-win-eventing-provider-l1-1-0.dll', False)])
- for debug_file, is_optional in debug_files:
- full_path = os.path.join(win_sdk_dir, 'Debuggers', target_cpu,
- debug_file)
- if not os.path.exists(full_path):
- if is_optional:
- continue
- else:
- raise Exception(
- '%s not found in "%s"\r\nYou must install'
- 'Windows 10 SDK version 10.0.19041.0 including the '
- '"Debugging Tools for Windows" feature.' %
- (debug_file, full_path))
- target_path = os.path.join(target_dir, debug_file)
- _CopyRuntimeImpl(target_path, full_path)
+ # List of debug files that should be copied, the first element of the tuple is
+ # the name of the file and the second indicates if it's optional.
+ debug_files = [('dbghelp.dll', False), ('dbgcore.dll', True)]
+ for debug_file, is_optional in debug_files:
+ full_path = os.path.join(win_sdk_dir, 'Debuggers', target_cpu, debug_file)
+ if not os.path.exists(full_path):
+ if is_optional:
+ continue
+ else:
+ # TODO(crbug.com/773476): remove version requirement.
+ raise Exception('%s not found in "%s"\r\nYou must install the '
+ '"Debugging Tools for Windows" feature from the Windows'
+ ' 10 SDK.'
+ % (debug_file, full_path))
+ target_path = os.path.join(target_dir, debug_file)
+ _CopyRuntimeImpl(target_path, full_path)
def _GetDesiredVsToolchainHashes():
- """Load a list of SHA1s corresponding to the toolchains that we want installed
+ """Load a list of SHA1s corresponding to the toolchains that we want installed
to build with."""
+ env_version = GetVisualStudioVersion()
+ if env_version == '2017':
+ # VS 2017 Update 9 (15.9.12) with 10.0.18362 SDK, 10.0.17763 version of
+ # Debuggers, and 10.0.17134 version of d3dcompiler_47.dll, with ARM64
+ # libraries.
+ toolchain_hash = '418b3076791776573a815eb298c8aa590307af63'
# Third parties that do not have access to the canonical toolchain can map
# canonical toolchain version to their own toolchain versions.
- toolchain_hash_mapping_key = 'GYP_MSVS_HASH_%s' % TOOLCHAIN_HASH
- return [os.environ.get(toolchain_hash_mapping_key, TOOLCHAIN_HASH)]
+ toolchain_hash_mapping_key = 'GYP_MSVS_HASH_%s' % toolchain_hash
+ return [os.environ.get(toolchain_hash_mapping_key, toolchain_hash)]
+ raise Exception('Unsupported VS version %s' % env_version)
def ShouldUpdateToolchain():
- """Check if the toolchain should be upgraded."""
- if not os.path.exists(json_data_file):
- return True
- with open(json_data_file, 'r') as tempf:
- toolchain_data = json.load(tempf)
- version = toolchain_data['version']
- env_version = GetVisualStudioVersion()
- # If there's a mismatch between the version set in the environment and the one
- # in the json file then the toolchain should be updated.
- return version != env_version
+ """Check if the toolchain should be upgraded."""
+ if not os.path.exists(json_data_file):
+ return True
+ with open(json_data_file, 'r') as tempf:
+ toolchain_data = json.load(tempf)
+ version = toolchain_data['version']
+ env_version = GetVisualStudioVersion()
+ # If there's a mismatch between the version set in the environment and the one
+ # in the json file then the toolchain should be updated.
+ return version != env_version
def Update(force=False, no_download=False):
- """Requests an update of the toolchain to the specific hashes we have at
+ """Requests an update of the toolchain to the specific hashes we have at
this revision. The update outputs a .json of the various configuration
information required to pass to gyp which we use in |GetToolchainDir()|.
If no_download is true then the toolchain will be configured if present but
will not be downloaded.
"""
- if force != False and force != '--force':
- print('Unknown parameter "%s"' % force, file=sys.stderr)
- return 1
- if force == '--force' or os.path.exists(json_data_file):
- force = True
+ if force != False and force != '--force':
+ print('Unknown parameter "%s"' % force, file=sys.stderr)
+ return 1
+ if force == '--force' or os.path.exists(json_data_file):
+ force = True
- depot_tools_win_toolchain = \
- bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
- if (_HostIsWindows() or force) and depot_tools_win_toolchain:
- import find_depot_tools
- depot_tools_path = find_depot_tools.add_depot_tools_to_path()
+ depot_tools_win_toolchain = \
+ bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
+ if ((sys.platform in ('win32', 'cygwin') or force) and
+ depot_tools_win_toolchain):
+ import find_depot_tools
+ depot_tools_path = find_depot_tools.add_depot_tools_to_path()
- # On Linux, the file system is usually case-sensitive while the Windows
- # SDK only works on case-insensitive file systems. If it doesn't already
- # exist, set up a ciopfs fuse mount to put the SDK in a case-insensitive
- # part of the file system.
- toolchain_dir = os.path.join(depot_tools_path, 'win_toolchain',
- 'vs_files')
- # For testing this block, unmount existing mounts with
- # fusermount -u third_party/depot_tools/win_toolchain/vs_files
- if sys.platform.startswith(
- 'linux') and not os.path.ismount(toolchain_dir):
- import distutils.spawn
- ciopfs = distutils.spawn.find_executable('ciopfs')
- if not ciopfs:
- # ciopfs not found in PATH; try the one downloaded from the DEPS hook.
- ciopfs = os.path.join(script_dir, 'ciopfs')
- if not os.path.isdir(toolchain_dir):
- os.mkdir(toolchain_dir)
- if not os.path.isdir(toolchain_dir + '.ciopfs'):
- os.mkdir(toolchain_dir + '.ciopfs')
- # Without use_ino, clang's #pragma once and Wnonportable-include-path
- # both don't work right, see https://llvm.org/PR34931
- # use_ino doesn't slow down builds, so it seems there's no drawback to
- # just using it always.
- subprocess.check_call([
- ciopfs, '-o', 'use_ino', toolchain_dir + '.ciopfs',
- toolchain_dir
- ])
+ # On Linux, the file system is usually case-sensitive while the Windows
+ # SDK only works on case-insensitive file systems. If it doesn't already
+ # exist, set up a ciopfs fuse mount to put the SDK in a case-insensitive
+ # part of the file system.
+ toolchain_dir = os.path.join(depot_tools_path, 'win_toolchain', 'vs_files')
+ # For testing this block, unmount existing mounts with
+ # fusermount -u third_party/depot_tools/win_toolchain/vs_files
+ if sys.platform.startswith('linux') and not os.path.ismount(toolchain_dir):
+ import distutils.spawn
+ ciopfs = distutils.spawn.find_executable('ciopfs')
+ if not ciopfs:
+ # ciopfs not found in PATH; try the one downloaded from the DEPS hook.
+ ciopfs = os.path.join(script_dir, 'ciopfs')
+ if not os.path.isdir(toolchain_dir):
+ os.mkdir(toolchain_dir)
+ if not os.path.isdir(toolchain_dir + '.ciopfs'):
+ os.mkdir(toolchain_dir + '.ciopfs')
+ # Without use_ino, clang's #pragma once and Wnonportable-include-path
+ # both don't work right, see https://llvm.org/PR34931
+ # use_ino doesn't slow down builds, so it seems there's no drawback to
+ # just using it always.
+ subprocess.check_call([
+ ciopfs, '-o', 'use_ino', toolchain_dir + '.ciopfs', toolchain_dir])
- get_toolchain_args = [
- # TODO(athom): use sys.executable (python3).
- # Note: depot_tools contains python.bat not python.exe
- # so for python to land on the first python in the PATH
- # irrespective of its extension we pass shell=True below.
- 'python',
- os.path.join(depot_tools_path, 'win_toolchain',
- 'get_toolchain_if_necessary.py'),
- '--output-json',
- json_data_file,
- ] + _GetDesiredVsToolchainHashes()
- if force:
- get_toolchain_args.append('--force')
- if no_download:
- get_toolchain_args.append('--no-download')
- subprocess.check_call(get_toolchain_args, shell=True)
+ # Necessary so that get_toolchain_if_necessary.py will put the VS toolkit
+ # in the correct directory.
+ os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion()
+ get_toolchain_args = [
+ sys.executable,
+ os.path.join(depot_tools_path,
+ 'win_toolchain',
+ 'get_toolchain_if_necessary.py'),
+ '--output-json', json_data_file,
+ ] + _GetDesiredVsToolchainHashes()
+ if force:
+ get_toolchain_args.append('--force')
+ if no_download:
+ get_toolchain_args.append('--no-download')
+ subprocess.check_call(get_toolchain_args)
- return 0
+ return 0
def NormalizePath(path):
- while path.endswith('\\'):
- path = path[:-1]
- return path
+ while path.endswith('\\'):
+ path = path[:-1]
+ return path
def SetEnvironmentAndGetSDKDir():
- """Gets location information about the current sdk (must have been
+ """Gets location information about the current sdk (must have been
previously updated by 'update'). This is used for the GN build."""
- SetEnvironmentAndGetRuntimeDllDirs()
+ SetEnvironmentAndGetRuntimeDllDirs()
- # If WINDOWSSDKDIR is not set, search the default SDK path and set it.
- if not 'WINDOWSSDKDIR' in os.environ:
- default_sdk_path = os.path.expandvars('%ProgramFiles(x86)%'
- '\\Windows Kits\\10')
- if os.path.isdir(default_sdk_path):
- os.environ['WINDOWSSDKDIR'] = default_sdk_path
+ # If WINDOWSSDKDIR is not set, search the default SDK path and set it.
+ if not 'WINDOWSSDKDIR' in os.environ:
+ default_sdk_path = os.path.expandvars('%ProgramFiles(x86)%'
+ '\\Windows Kits\\10')
+ if os.path.isdir(default_sdk_path):
+ os.environ['WINDOWSSDKDIR'] = default_sdk_path
- return NormalizePath(os.environ['WINDOWSSDKDIR'])
+ return NormalizePath(os.environ['WINDOWSSDKDIR'])
def GetToolchainDir():
- """Gets location information about the current toolchain (must have been
+ """Gets location information about the current toolchain (must have been
previously updated by 'update'). This is used for the GN build."""
- runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
- win_sdk_dir = SetEnvironmentAndGetSDKDir()
+ runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
+ win_sdk_dir = SetEnvironmentAndGetSDKDir()
- print('''vs_path = %s
+ print('''vs_path = %s
sdk_path = %s
vs_version = %s
wdk_dir = %s
@@ -584,16 +540,16 @@
def main():
- commands = {
- 'update': Update,
- 'get_toolchain_dir': GetToolchainDir,
- 'copy_dlls': CopyDlls,
- }
- if len(sys.argv) < 2 or sys.argv[1] not in commands:
- print('Expected one of: %s' % ', '.join(commands), file=sys.stderr)
- return 1
- return commands[sys.argv[1]](*sys.argv[2:])
+ commands = {
+ 'update': Update,
+ 'get_toolchain_dir': GetToolchainDir,
+ 'copy_dlls': CopyDlls,
+ }
+ if len(sys.argv) < 2 or sys.argv[1] not in commands:
+ print('Expected one of: %s' % ', '.join(commands), file=sys.stderr)
+ return 1
+ return commands[sys.argv[1]](*sys.argv[2:])
if __name__ == '__main__':
- sys.exit(main())
+ sys.exit(main())
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/api/code.dart b/pkg/_fe_analyzer_shared/lib/src/macros/api/code.dart
index e0a09f2..de81796 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/api/code.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/api/code.dart
@@ -251,7 +251,7 @@
this[i],
separator,
],
- last,
+ if (isNotEmpty) last,
];
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart b/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
index 59b7a26..18ceb87 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
@@ -34,7 +34,7 @@
}
constructorEntries.writeln('},');
});
- constructorEntries.writeln("}");
+ constructorEntries.writeln('},');
});
return template
.replaceFirst(_importMarker, imports.toString())
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 830127a..36c0cb7 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -7024,6 +7024,67 @@
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String name)>
+ templateJsInteropStaticInteropTrustTypesUsageNotAllowed =
+ const Template<Message Function(String name)>(
+ problemMessageTemplate:
+ r"""JS interop class '#name' has an `@trustTypes` annotation, but `@trustTypes` is only supported within the sdk.""",
+ correctionMessageTemplate:
+ r"""Try removing the `@trustTypes` annotation.""",
+ withArguments:
+ _withArgumentsJsInteropStaticInteropTrustTypesUsageNotAllowed);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+ codeJsInteropStaticInteropTrustTypesUsageNotAllowed =
+ const Code<Message Function(String name)>(
+ "JsInteropStaticInteropTrustTypesUsageNotAllowed",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsJsInteropStaticInteropTrustTypesUsageNotAllowed(
+ String name) {
+ if (name.isEmpty) throw 'No name provided';
+ name = demangleMixinApplicationName(name);
+ return new Message(codeJsInteropStaticInteropTrustTypesUsageNotAllowed,
+ problemMessage:
+ """JS interop class '${name}' has an `@trustTypes` annotation, but `@trustTypes` is only supported within the sdk.""",
+ correctionMessage: """Try removing the `@trustTypes` annotation.""",
+ arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name)>
+ templateJsInteropStaticInteropTrustTypesUsedWithoutStaticInterop =
+ const Template<Message Function(String name)>(
+ problemMessageTemplate:
+ r"""JS interop class '#name' has an `@trustTypes` annotation, but no `@staticInterop` annotation.""",
+ correctionMessageTemplate:
+ r"""Try marking the class using `@staticInterop`.""",
+ withArguments:
+ _withArgumentsJsInteropStaticInteropTrustTypesUsedWithoutStaticInterop);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+ codeJsInteropStaticInteropTrustTypesUsedWithoutStaticInterop =
+ const Code<Message Function(String name)>(
+ "JsInteropStaticInteropTrustTypesUsedWithoutStaticInterop",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsJsInteropStaticInteropTrustTypesUsedWithoutStaticInterop(
+ String name) {
+ if (name.isEmpty) throw 'No name provided';
+ name = demangleMixinApplicationName(name);
+ return new Message(
+ codeJsInteropStaticInteropTrustTypesUsedWithoutStaticInterop,
+ problemMessage:
+ """JS interop class '${name}' has an `@trustTypes` annotation, but no `@staticInterop` annotation.""",
+ correctionMessage: """Try marking the class using `@staticInterop`.""",
+ arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name)>
templateJsInteropStaticInteropWithInstanceMembers =
const Template<Message Function(String name)>(
problemMessageTemplate:
diff --git a/pkg/_js_interop_checks/lib/js_interop_checks.dart b/pkg/_js_interop_checks/lib/js_interop_checks.dart
index 13917c7..351c410 100644
--- a/pkg/_js_interop_checks/lib/js_interop_checks.dart
+++ b/pkg/_js_interop_checks/lib/js_interop_checks.dart
@@ -22,7 +22,9 @@
templateJsInteropStaticInteropWithInstanceMembers,
templateJsInteropStaticInteropWithNonStaticSupertype,
templateJsInteropJSClassExtendsDartClass,
- templateJsInteropNativeClassInAnnotation;
+ templateJsInteropNativeClassInAnnotation,
+ templateJsInteropStaticInteropTrustTypesUsageNotAllowed,
+ templateJsInteropStaticInteropTrustTypesUsedWithoutStaticInterop;
import 'src/js_interop.dart';
@@ -39,7 +41,6 @@
/// Libraries that use `external` to exclude from checks on external.
static final Iterable<String> _pathsWithAllowedDartExternalUsage = <String>[
'_foreign_helper', // for foreign helpers
- '_late_helper', // for dart2js late variable utilities
'_interceptors', // for ddc JS string
'_native_typed_data',
'_runtime', // for ddc types at runtime
@@ -67,6 +68,11 @@
'generated_tests/web_2/native/native_test',
];
+ List<Pattern> _allowedTrustTypesTestPatterns = [
+ RegExp(r'(?<!generated_)tests/lib/js'),
+ RegExp(r'(?<!generated_)tests/lib_2/js'),
+ ];
+
bool _libraryIsGlobalNamespace = false;
JsInteropChecks(
@@ -104,6 +110,25 @@
_classHasJSAnnotation = hasJSInteropAnnotation(cls);
_classHasAnonymousAnnotation = hasAnonymousAnnotation(cls);
_classHasStaticInteropAnnotation = hasStaticInteropAnnotation(cls);
+ bool classHasTrustTypesAnnotation = hasTrustTypesAnnotation(cls);
+ if (classHasTrustTypesAnnotation) {
+ if (!_isAllowedTrustTypesUsage(cls)) {
+ _diagnosticsReporter.report(
+ templateJsInteropStaticInteropTrustTypesUsageNotAllowed
+ .withArguments(cls.name),
+ cls.fileOffset,
+ cls.name.length,
+ cls.fileUri);
+ }
+ if (!_classHasStaticInteropAnnotation) {
+ _diagnosticsReporter.report(
+ templateJsInteropStaticInteropTrustTypesUsedWithoutStaticInterop
+ .withArguments(cls.name),
+ cls.fileOffset,
+ cls.name.length,
+ cls.fileUri);
+ }
+ }
var superclass = cls.superclass;
if (superclass != null && superclass != _coreTypes.objectClass) {
var superHasJSAnnotation = hasJSInteropAnnotation(superclass);
@@ -357,6 +382,14 @@
}
}
+ /// Verifies that use of `@trustTypes` is allowed.
+ bool _isAllowedTrustTypesUsage(Class cls) {
+ Uri uri = cls.enclosingLibrary.importUri;
+ return uri.isScheme('dart') && uri.path == 'ui' ||
+ _allowedTrustTypesTestPatterns
+ .any((pattern) => uri.path.contains(pattern));
+ }
+
/// Verifies given member is one of the allowed usages of external:
/// a dart low level library, a foreign helper, a native test,
/// or a from environment constructor.
diff --git a/pkg/_js_interop_checks/lib/src/js_interop.dart b/pkg/_js_interop_checks/lib/src/js_interop.dart
index 9874a1c..3f3c517 100644
--- a/pkg/_js_interop_checks/lib/src/js_interop.dart
+++ b/pkg/_js_interop_checks/lib/src/js_interop.dart
@@ -20,6 +20,11 @@
bool hasStaticInteropAnnotation(Annotatable a) =>
a.annotations.any(_isStaticInteropAnnotation);
+/// Returns true iff the node has an `@trustTypes` annotation from
+/// `package:js` or from the internal `dart:_js_annotations`.
+bool hasTrustTypesAnnotation(Annotatable a) =>
+ a.annotations.any(_isTrustTypesAnnotation);
+
/// If [a] has a `@JS('...')` annotation, returns the value inside the
/// parentheses.
///
@@ -80,6 +85,9 @@
bool _isStaticInteropAnnotation(Expression value) =>
_isInteropAnnotation(value, '_StaticInterop');
+bool _isTrustTypesAnnotation(Expression value) =>
+ _isInteropAnnotation(value, '_TrustTypes');
+
/// Returns true if [value] is the `Native` annotation from `dart:_js_helper`.
bool _isNativeAnnotation(Expression value) {
var c = _annotationClass(value);
diff --git a/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart b/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart
index 57b3a31..5205099 100644
--- a/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart
+++ b/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart
@@ -7,16 +7,19 @@
import 'package:kernel/core_types.dart';
import 'package:kernel/type_environment.dart';
-import '../js_interop.dart' show getJSName;
+import '../js_interop.dart' show getJSName, hasTrustTypesAnnotation;
/// Replaces js_util methods with inline calls to foreign_helper JS which
/// emits the code as a JavaScript code fragment.
class JsUtilOptimizer extends Transformer {
final Procedure _callMethodTarget;
+ final Procedure _callMethodTrustTypeTarget;
final List<Procedure> _callMethodUncheckedTargets;
+ final List<Procedure> _callMethodUncheckedTrustTypeTargets;
final Procedure _callConstructorTarget;
final List<Procedure> _callConstructorUncheckedTargets;
final Procedure _getPropertyTarget;
+ final Procedure _getPropertyTrustTypeTarget;
final Procedure _setPropertyTarget;
final Procedure _setPropertyUncheckedTarget;
@@ -37,14 +40,21 @@
final CoreTypes _coreTypes;
final StatefulStaticTypeContext _staticTypeContext;
Map<Reference, ExtensionMemberDescriptor>? _extensionMemberIndex;
+ late Set<Reference> _shouldTrustType;
JsUtilOptimizer(this._coreTypes, ClassHierarchy hierarchy)
: _callMethodTarget =
_coreTypes.index.getTopLevelProcedure('dart:js_util', 'callMethod'),
+ _callMethodTrustTypeTarget = _coreTypes.index
+ .getTopLevelProcedure('dart:js_util', '_callMethodTrustType'),
_callMethodUncheckedTargets = List<Procedure>.generate(
5,
(i) => _coreTypes.index.getTopLevelProcedure(
'dart:js_util', '_callMethodUnchecked$i')),
+ _callMethodUncheckedTrustTypeTargets = List<Procedure>.generate(
+ 5,
+ (i) => _coreTypes.index.getTopLevelProcedure(
+ 'dart:js_util', '_callMethodUncheckedTrustType$i')),
_callConstructorTarget = _coreTypes.index
.getTopLevelProcedure('dart:js_util', 'callConstructor'),
_callConstructorUncheckedTargets = List<Procedure>.generate(
@@ -53,6 +63,8 @@
'dart:js_util', '_callConstructorUnchecked$i')),
_getPropertyTarget = _coreTypes.index
.getTopLevelProcedure('dart:js_util', 'getProperty'),
+ _getPropertyTrustTypeTarget = _coreTypes.index
+ .getTopLevelProcedure('dart:js_util', '_getPropertyTrustType'),
_setPropertyTarget = _coreTypes.index
.getTopLevelProcedure('dart:js_util', 'setProperty'),
_setPropertyUncheckedTarget = _coreTypes.index
@@ -93,14 +105,16 @@
if (node.isExternal && node.isExtensionMember) {
var index = _extensionMemberIndex ??=
_createExtensionMembersIndex(node.enclosingLibrary);
- var nodeDescriptor = index[node.reference]!;
+ Reference reference = node.reference;
+ var nodeDescriptor = index[reference]!;
+ bool shouldTrustType = _shouldTrustType.contains(reference);
if (!nodeDescriptor.isStatic) {
if (nodeDescriptor.kind == ExtensionMemberKind.Getter) {
- transformedBody = _getExternalGetterBody(node);
+ transformedBody = _getExternalGetterBody(node, shouldTrustType);
} else if (nodeDescriptor.kind == ExtensionMemberKind.Setter) {
transformedBody = _getExternalSetterBody(node);
} else if (nodeDescriptor.kind == ExtensionMemberKind.Method) {
- transformedBody = _getExternalMethodBody(node);
+ transformedBody = _getExternalMethodBody(node, shouldTrustType);
}
}
}
@@ -120,9 +134,17 @@
Map<Reference, ExtensionMemberDescriptor> _createExtensionMembersIndex(
Library library) {
_extensionMemberIndex = {};
- library.extensions.forEach((extension) => extension.members.forEach(
- (descriptor) =>
- _extensionMemberIndex![descriptor.member] = descriptor));
+ _shouldTrustType = {};
+ library.extensions
+ .forEach((extension) => extension.members.forEach((descriptor) {
+ Reference reference = descriptor.member;
+ _extensionMemberIndex![reference] = descriptor;
+ DartType onType = extension.onType;
+ if (onType is InterfaceType &&
+ hasTrustTypesAnnotation(onType.className.asClass)) {
+ _shouldTrustType.add(reference);
+ }
+ }));
return _extensionMemberIndex!;
}
@@ -130,11 +152,13 @@
///
/// The new function body will call the optimized version of
/// `js_util.getProperty` for the given external getter.
- ReturnStatement _getExternalGetterBody(Procedure node) {
+ ReturnStatement _getExternalGetterBody(Procedure node, bool shouldTrustType) {
var function = node.function;
assert(function.positionalParameters.length == 1);
+ Procedure target =
+ shouldTrustType ? _getPropertyTrustTypeTarget : _getPropertyTarget;
var getPropertyInvocation = StaticInvocation(
- _getPropertyTarget,
+ target,
Arguments([
VariableGet(function.positionalParameters.first),
StringLiteral(_getExtensionMemberName(node))
@@ -170,10 +194,12 @@
///
/// The new function body will call the optimized version of
/// `js_util.callMethod` for the given external method.
- ReturnStatement _getExternalMethodBody(Procedure node) {
+ ReturnStatement _getExternalMethodBody(Procedure node, bool shouldTrustType) {
var function = node.function;
+ Procedure target =
+ shouldTrustType ? _callMethodTrustTypeTarget : _callMethodTarget;
var callMethodInvocation = StaticInvocation(
- _callMethodTarget,
+ target,
Arguments([
VariableGet(function.positionalParameters.first),
StringLiteral(_getExtensionMemberName(node)),
@@ -185,7 +211,8 @@
function.returnType
]))
..fileOffset = node.fileOffset;
- return ReturnStatement(_lowerCallMethod(callMethodInvocation));
+ return ReturnStatement(_lowerCallMethod(callMethodInvocation,
+ shouldTrustType: shouldTrustType));
}
/// Returns the extension member name.
@@ -214,7 +241,8 @@
if (node.target == _setPropertyTarget) {
node = _lowerSetProperty(node);
} else if (node.target == _callMethodTarget) {
- node = _lowerCallMethod(node);
+ // Never trust types on explicit `js_util` calls.
+ node = _lowerCallMethod(node, shouldTrustType: false);
} else if (node.target == _callConstructorTarget) {
node = _lowerCallConstructor(node);
}
@@ -245,13 +273,17 @@
/// Calls will be lowered when using a List literal or constant list with 0-4
/// elements for the `callMethod` arguments, or the `List.empty()` factory.
/// Removing the checks allows further inlining by the compilers.
- StaticInvocation _lowerCallMethod(StaticInvocation node) {
+ StaticInvocation _lowerCallMethod(StaticInvocation node,
+ {required bool shouldTrustType}) {
Arguments arguments = node.arguments;
assert(arguments.positional.length == 3);
assert(arguments.named.isEmpty);
+ List<Procedure> targets = shouldTrustType
+ ? _callMethodUncheckedTrustTypeTargets
+ : _callMethodUncheckedTargets;
return _lowerToCallUnchecked(
- node, _callMethodUncheckedTargets, arguments.positional.sublist(0, 2));
+ node, targets, arguments.positional.sublist(0, 2));
}
/// Lowers the given js_util `callConstructor` call to `_callConstructorUncheckedN`
diff --git a/pkg/analysis_server/test/integration/server/bazel_changes_test.dart b/pkg/analysis_server/test/integration/server/bazel_changes_test.dart
index 3a64173..5dd8d39 100644
--- a/pkg/analysis_server/test/integration/server/bazel_changes_test.dart
+++ b/pkg/analysis_server/test/integration/server/bazel_changes_test.dart
@@ -127,7 +127,9 @@
await processedNotification.future;
expect(errors, isNotEmpty);
- expect(errors[0].message, contains('generated.dart'));
+ var error = errors.singleWhere((e) => e.code == 'uri_does_not_exist',
+ orElse: () => throw "'uri_does_not_exist' error was not found");
+ expect(error.message, contains('generated.dart'));
// This seems to be necessary (at least when running the test from source),
// because it takes a while for the watcher isolate to start.
diff --git a/pkg/analysis_server/test/lsp/diagnostic_test.dart b/pkg/analysis_server/test/lsp/diagnostic_test.dart
index c5024cb..0c6572e 100644
--- a/pkg/analysis_server/test/lsp/diagnostic_test.dart
+++ b/pkg/analysis_server/test/lsp/diagnostic_test.dart
@@ -5,6 +5,7 @@
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
+import 'package:linter/src/rules.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -378,6 +379,71 @@
}
}
+ /// Tests that diagnostic ordering is stable when minor changes are made to
+ /// the file that does not alter the diagnostics besides extending their
+ /// range and adding to their messages.
+ ///
+ /// https://github.com/Dart-Code/Dart-Code/issues/3934
+ Future<void> test_stableOrder() async {
+ /// Helper to pad out the content in a way that has previously triggered
+ /// this issue.
+ String wrappedContent(String content) => '''
+//
+//
+//
+//
+
+void f() {
+ $content
+}
+''';
+
+ registerLintRules();
+ newFile(analysisOptionsPath, '''
+linter:
+ rules:
+ - prefer_typing_uninitialized_variables
+
+analyzer:
+ language:
+ strict-inference: true
+ ''');
+
+ newFile(mainFilePath, '');
+ await initialize();
+ await openFile(mainFileUri, '');
+
+ // Collect the initial set of diagnostic to compare against.
+ var docVersion = 1;
+ final originalDiagnosticsUpdate = waitForDiagnostics(mainFileUri);
+ await replaceFile(docVersion++, mainFileUri, wrappedContent('final bar;'));
+ final originalDiagnostics = await originalDiagnosticsUpdate;
+
+ // Helper to update the content and verify the same diagnostics are returned
+ // in the same order, despite the changes to offset/message altering
+ // hashcodes.
+ Future<void> verifyDiagnostics(String content) async {
+ final diagnosticsUpdate = waitForDiagnostics(mainFileUri);
+ await replaceFile(docVersion++, mainFileUri, wrappedContent(content));
+ final diagnostics = await diagnosticsUpdate;
+ expect(
+ diagnostics!.map((d) => d.code),
+ originalDiagnostics!.map((d) => d.code),
+ );
+ }
+
+ // These changes do not affect the errors being produced (besides offset/
+ // message text) but will cause hashcode changes that previously altered the
+ // returned order.
+ await verifyDiagnostics('final dbar;');
+ await verifyDiagnostics('final dybar;');
+ await verifyDiagnostics('final dynbar;');
+ await verifyDiagnostics('final dynabar;');
+ await verifyDiagnostics('final dynambar;');
+ await verifyDiagnostics('final dynamibar;');
+ await verifyDiagnostics('final dynamicbar;');
+ }
+
Future<void> test_todos_boolean() async {
// TODOs only show up if there's also some code in the file.
const contents = '''
diff --git a/pkg/analyzer/lib/error/listener.dart b/pkg/analyzer/lib/error/listener.dart
index 88555b2..c21fe48 100644
--- a/pkg/analyzer/lib/error/listener.dart
+++ b/pkg/analyzer/lib/error/listener.dart
@@ -2,8 +2,6 @@
// 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.
-import 'dart:collection';
-
import 'package:analyzer/dart/ast/ast.dart'
show AstNode, ConstructorDeclaration;
import 'package:analyzer/dart/ast/token.dart';
@@ -257,7 +255,7 @@
@override
void onError(AnalysisError error) {
- (_errors ??= HashSet<AnalysisError>()).add(error);
+ (_errors ??= {}).add(error);
}
}
diff --git a/pkg/analyzer/lib/src/summary2/macro_application.dart b/pkg/analyzer/lib/src/summary2/macro_application.dart
index 9f618ae..1931e3b 100644
--- a/pkg/analyzer/lib/src/summary2/macro_application.dart
+++ b/pkg/analyzer/lib/src/summary2/macro_application.dart
@@ -172,6 +172,30 @@
);
}
+ static macro.ParameterDeclarationImpl _buildFormalParameter(
+ FormalParameter node,
+ ) {
+ if (node is DefaultFormalParameter) {
+ node = node.parameter;
+ }
+
+ final macro.TypeAnnotationImpl typeAnnotation;
+ if (node is SimpleFormalParameter) {
+ typeAnnotation = _buildTypeAnnotation(node.type);
+ } else {
+ throw UnimplementedError('(${node.runtimeType}) $node');
+ }
+
+ return macro.ParameterDeclarationImpl(
+ id: macro.RemoteInstance.uniqueId,
+ identifier:
+ _buildIdentifier(node.identifier!), // TODO(scheglov) might be null
+ isNamed: node.isNamed,
+ isRequired: node.isRequired,
+ type: typeAnnotation,
+ );
+ }
+
static macro.IdentifierImpl _buildIdentifier(Identifier node) {
final String name;
if (node is SimpleIdentifier) {
@@ -185,8 +209,27 @@
);
}
- static macro.TypeAnnotationImpl _buildTypeAnnotation(TypeAnnotation node) {
- if (node is NamedType) {
+ static macro.TypeAnnotationImpl _buildTypeAnnotation(TypeAnnotation? node) {
+ if (node == null) {
+ return macro.OmittedTypeAnnotationImpl(
+ id: macro.RemoteInstance.uniqueId,
+ );
+ } else if (node is GenericFunctionType) {
+ return macro.FunctionTypeAnnotationImpl(
+ id: macro.RemoteInstance.uniqueId,
+ isNullable: node.question != null,
+ namedParameters: node.parameters.parameters
+ .where((e) => e.isNamed)
+ .map(_buildFormalParameter)
+ .toList(),
+ positionalParameters: node.parameters.parameters
+ .where((e) => e.isPositional)
+ .map(_buildFormalParameter)
+ .toList(),
+ returnType: _buildTypeAnnotation(node.returnType),
+ typeParameters: _buildTypeParameters(node.typeParameters),
+ );
+ } else if (node is NamedType) {
return macro.NamedTypeAnnotationImpl(
id: macro.RemoteInstance.uniqueId,
identifier: _buildIdentifier(node.name),
@@ -262,22 +305,38 @@
return -operandValue;
}
} else if (node is SetOrMapLiteral) {
- final result = <Object?, Object?>{};
- for (final element in node.elements) {
- if (element is! MapLiteralEntry) {
- _throwError(element, 'MapLiteralEntry expected');
- }
- final key = evaluate(element.key);
- final value = evaluate(element.value);
- result[key] = value;
- }
- return result;
+ return _setOrMapLiteral(node);
} else if (node is SimpleStringLiteral) {
return node.value;
}
_throwError(node, 'Not supported: ${node.runtimeType}');
}
+ Object _setOrMapLiteral(SetOrMapLiteral node) {
+ if (node.elements.every((e) => e is Expression)) {
+ final result = <Object?>{};
+ for (final element in node.elements) {
+ if (element is! Expression) {
+ _throwError(element, 'Expression expected');
+ }
+ final value = evaluate(element);
+ result.add(value);
+ }
+ return result;
+ }
+
+ final result = <Object?, Object?>{};
+ for (final element in node.elements) {
+ if (element is! MapLiteralEntry) {
+ _throwError(element, 'MapLiteralEntry expected');
+ }
+ final key = evaluate(element.key);
+ final value = evaluate(element.value);
+ result[key] = value;
+ }
+ return result;
+ }
+
Never _throwError(AstNode node, String message) {
throw ArgumentMacroApplicationError(
annotationIndex: annotationIndex,
diff --git a/pkg/analyzer/lib/src/summary2/macro_application_error.dart b/pkg/analyzer/lib/src/summary2/macro_application_error.dart
index a7b9018..de56919 100644
--- a/pkg/analyzer/lib/src/summary2/macro_application_error.dart
+++ b/pkg/analyzer/lib/src/summary2/macro_application_error.dart
@@ -33,7 +33,8 @@
@override
String toStringForTest() {
- return 'Argument(annotation: $annotationIndex, argument: $argumentIndex)';
+ return 'Argument(annotation: $annotationIndex, '
+ 'argument: $argumentIndex, message: $message)';
}
@override
@@ -118,7 +119,7 @@
@override
String toStringForTest() {
- return 'Unknown(annotation: $annotationIndex)';
+ return 'Unknown(annotation: $annotationIndex, message: $message)';
}
@override
diff --git a/pkg/analyzer/test/error/error_listener_test.dart b/pkg/analyzer/test/error/error_listener_test.dart
new file mode 100644
index 0000000..25a0b3b
--- /dev/null
+++ b/pkg/analyzer/test/error/error_listener_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2022, 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.
+
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(RecordingErrorListenerTest);
+ });
+}
+
+@reflectiveTest
+class RecordingErrorListenerTest {
+ test_orderedAsReported() {
+ final listener = RecordingErrorListener();
+ listener.onError(_MockAnalysisError(expectedIndex: 0, hashCode: 1));
+ listener.onError(_MockAnalysisError(expectedIndex: 1, hashCode: 10));
+ listener.onError(_MockAnalysisError(expectedIndex: 2, hashCode: -50));
+ listener.onError(_MockAnalysisError(expectedIndex: 3, hashCode: 20));
+ listener.onError(_MockAnalysisError(expectedIndex: 4, hashCode: 1));
+
+ // Expect the errors are returned in the order they are reported, and not
+ // affected by their hashcodes.
+ expect(
+ listener.errors.cast<_MockAnalysisError>().map((e) => e.expectedIndex),
+ [0, 1, 2, 3, 4],
+ );
+ }
+}
+
+/// An [AnalysisError] that allows setting an explicit hash code.
+class _MockAnalysisError implements AnalysisError {
+ @override
+ int hashCode;
+
+ int expectedIndex;
+
+ _MockAnalysisError({required this.expectedIndex, required this.hashCode});
+
+ @override
+ dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analyzer/test/error/test_all.dart b/pkg/analyzer/test/error/test_all.dart
index 19eca56..684e462 100644
--- a/pkg/analyzer/test/error/test_all.dart
+++ b/pkg/analyzer/test/error/test_all.dart
@@ -4,11 +4,13 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'error_listener_test.dart' as error_listener;
import 'error_reporter_test.dart' as error_reporter;
import 'error_test.dart' as error_test;
main() {
defineReflectiveSuite(() {
+ error_listener.main();
error_reporter.main();
error_test.main();
}, name: 'error');
diff --git a/pkg/analyzer/test/src/summary/macro/declaration_text.dart b/pkg/analyzer/test/src/summary/macro/declaration_text.dart
index 066c9b6..85ec1ed 100644
--- a/pkg/analyzer/test/src/summary/macro/declaration_text.dart
+++ b/pkg/analyzer/test/src/summary/macro/declaration_text.dart
@@ -131,15 +131,12 @@
_TypeStringBuilder(this._sink);
void write(TypeAnnotation type) {
- if (type is NamedTypeAnnotation) {
- _sink.write(type.identifier.name);
- _sink.writeList(
- elements: type.typeArguments,
- write: write,
- separator: ', ',
- open: '<',
- close: '>',
- );
+ if (type is FunctionTypeAnnotation) {
+ _writeFunctionTypeAnnotation(type);
+ } else if (type is NamedTypeAnnotation) {
+ _writeNamedTypeAnnotation(type);
+ } else if (type is OmittedTypeAnnotation) {
+ _sink.write('OmittedType');
} else {
throw UnimplementedError('(${type.runtimeType}) $type');
}
@@ -147,6 +144,80 @@
_sink.write('?');
}
}
+
+ void _writeFormalParameter(ParameterDeclaration node) {
+ final String closeSeparator;
+ if (node.isNamed) {
+ _sink.write('{');
+ closeSeparator = '}';
+ if (node.isRequired) {
+ _sink.write('required ');
+ }
+ } else if (!node.isRequired) {
+ _sink.write('[');
+ closeSeparator = ']';
+ } else {
+ closeSeparator = '';
+ }
+
+ write(node.type);
+ _sink.write(' ');
+ _sink.write(node.identifier.name);
+
+ _sink.write(closeSeparator);
+ }
+
+ void _writeFunctionTypeAnnotation(FunctionTypeAnnotation type) {
+ write(type.returnType);
+ _sink.write(' Function');
+
+ _sink.writeList(
+ elements: type.typeParameters,
+ write: _writeTypeParameter,
+ separator: ', ',
+ open: '<',
+ close: '>',
+ );
+
+ _sink.write('(');
+ var hasFormalParameter = false;
+ for (final formalParameter in type.positionalParameters) {
+ if (hasFormalParameter) {
+ _sink.write(', ');
+ }
+ _writeFormalParameter(formalParameter);
+ hasFormalParameter = true;
+ }
+ for (final formalParameter in type.namedParameters) {
+ if (hasFormalParameter) {
+ _sink.write(', ');
+ }
+ _writeFormalParameter(formalParameter);
+ hasFormalParameter = true;
+ }
+ _sink.write(')');
+ }
+
+ void _writeNamedTypeAnnotation(NamedTypeAnnotation type) {
+ _sink.write(type.identifier.name);
+ _sink.writeList(
+ elements: type.typeArguments,
+ write: write,
+ separator: ', ',
+ open: '<',
+ close: '>',
+ );
+ }
+
+ void _writeTypeParameter(TypeParameterDeclaration node) {
+ _sink.write(node.identifier.name);
+
+ final bound = node.bound;
+ if (bound != null) {
+ _sink.write(' extends ');
+ write(bound);
+ }
+ }
}
extension on StringSink {
@@ -158,22 +229,24 @@
String? close,
}) {
elements = elements.toList();
- if (elements.isNotEmpty) {
- if (open != null) {
- this.write(open);
+ if (elements.isEmpty) {
+ return;
+ }
+
+ if (open != null) {
+ this.write(open);
+ }
+ var isFirst = true;
+ for (var element in elements) {
+ if (isFirst) {
+ isFirst = false;
+ } else {
+ this.write(separator);
}
- var isFirst = true;
- for (var element in elements) {
- if (isFirst) {
- isFirst = false;
- } else {
- this.write(separator);
- }
- write(element);
- }
- if (close != null) {
- this.write(close);
- }
+ write(element);
+ }
+ if (close != null) {
+ this.write(close);
}
}
}
diff --git a/pkg/analyzer/test/src/summary/macro_test.dart b/pkg/analyzer/test/src/summary/macro_test.dart
index 0c3f764..f21ac8a 100644
--- a/pkg/analyzer/test/src/summary/macro_test.dart
+++ b/pkg/analyzer/test/src/summary/macro_test.dart
@@ -5,6 +5,7 @@
import 'package:_fe_analyzer_shared/src/macros/executor/multi_executor.dart'
as macro;
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/summary2/kernel_compilation_service.dart';
import 'package:analyzer/src/summary2/macro.dart';
@@ -83,7 +84,8 @@
},
constructorParametersCode: '(this.foo, this.bar)',
argumentsCode: '(0, const Object())',
- expectedErrors: 'Argument(annotation: 0, argument: 1)',
+ expectedErrors: 'Argument(annotation: 0, argument: 1, '
+ 'message: Not supported: InstanceCreationExpressionImpl)',
);
}
@@ -235,6 +237,19 @@
);
}
+ test_arguments_typesPhase_type_set() async {
+ await _assertTypesPhaseArgumentsText(
+ fields: {
+ 'foo': 'Set<Object?>',
+ },
+ constructorParametersCode: '(this.foo)',
+ argumentsCode: '({1, 2, 3})',
+ expected: r'''
+foo: {1, 2, 3}
+''',
+ );
+ }
+
test_arguments_typesPhase_type_string() async {
await _assertTypesPhaseArgumentsText(
fields: {'foo': 'String'},
@@ -385,6 +400,88 @@
''');
}
+ test_introspect_types_functionTypeAnnotation_formalParameters_namedOptional_simpleFormalParameter() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function(int a, {int? b, int? c})> {}
+''', r'''
+class A
+ superclass: B<void Function(int a, {int? b}, {int? c})>
+''');
+ }
+
+ test_introspect_types_functionTypeAnnotation_formalParameters_namedRequired_simpleFormalParameter() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function(int a, {required int b, required int c})> {}
+''', r'''
+class A
+ superclass: B<void Function(int a, {required int b}, {required int c})>
+''');
+ }
+
+ test_introspect_types_functionTypeAnnotation_formalParameters_positionalOptional_simpleFormalParameter() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function(int a, [int b, int c])> {}
+''', r'''
+class A
+ superclass: B<void Function(int a, [int b], [int c])>
+''');
+ }
+
+ /// TODO(scheglov) Tests for unnamed positional formal parameters.
+ test_introspect_types_functionTypeAnnotation_formalParameters_positionalRequired_simpleFormalParameter() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function(int a, double b)> {}
+''', r'''
+class A
+ superclass: B<void Function(int a, double b)>
+''');
+ }
+
+ test_introspect_types_functionTypeAnnotation_nullable() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function()?> {}
+''', r'''
+class A
+ superclass: B<void Function()?>
+''');
+ }
+
+ test_introspect_types_functionTypeAnnotation_returnType() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function()> {}
+''', r'''
+class A
+ superclass: B<void Function()>
+''');
+ }
+
+ test_introspect_types_functionTypeAnnotation_returnType_omitted() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<Function()> {}
+''', r'''
+class A
+ superclass: B<OmittedType Function()>
+''');
+ }
+
+ test_introspect_types_functionTypeAnnotation_typeParameters() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends B<void Function<T, U extends num>()> {}
+''', r'''
+class A
+ superclass: B<void Function<T, U extends num>()>
+''');
+ }
+
+ test_introspect_types_namedTypeAnnotation_prefixed() async {
+ await _assertTypesPhaseIntrospectionText(r'''
+class A extends prefix.B {}
+''', r'''
+class A
+ superclass: B
+''');
+ }
+
test_macroFlag_class() async {
var library = await buildLibrary(r'''
macro class A {}
@@ -504,6 +601,14 @@
{'package:test/arguments_text.dart'}
]);
+ final A = library.definingCompilationUnit.getType('A');
+ if (expectedErrors != null) {
+ expect(_errorsStrForClassElement(A), expectedErrors);
+ return;
+ } else {
+ _assertNoErrorsForClassElement(A);
+ }
+
if (expected != null) {
final x = library.parts.single.topLevelVariables.single;
expect(x.name, 'x');
@@ -514,13 +619,6 @@
print(actual);
}
expect(actual, expected);
- } else if (expectedErrors != null) {
- var A = library.definingCompilationUnit.getType('A');
- A as ClassElementImpl;
- expect(
- A.macroApplicationErrors.map((e) => e.toStringForTest()).join('\n'),
- expectedErrors,
- );
} else {
fail("Either 'expected' or 'expectedErrors' must be provided.");
}
@@ -561,10 +659,26 @@
{'package:test/declaration_text.dart'}
]);
+ _assertNoErrorsForClassElement(
+ library.definingCompilationUnit.getType('A'),
+ );
+
var x = library.parts.single.topLevelVariables.single;
expect(x.name, 'x');
x as ConstTopLevelVariableElementImpl;
var x_literal = x.constantInitializer as SimpleStringLiteral;
return x_literal.value;
}
+
+ static void _assertNoErrorsForClassElement(ClassElement? element) {
+ var actual = _errorsStrForClassElement(element);
+ expect(actual, isEmpty);
+ }
+
+ static String _errorsStrForClassElement(ClassElement? element) {
+ element as ClassElementImpl;
+ return element.macroApplicationErrors.map((e) {
+ return e.toStringForTest();
+ }).join('\n');
+ }
}
diff --git a/pkg/compiler/lib/compiler.dart b/pkg/compiler/lib/compiler.dart
index 9b2f5c1..5fd5ff1 100644
--- a/pkg/compiler/lib/compiler.dart
+++ b/pkg/compiler/lib/compiler.dart
@@ -10,7 +10,7 @@
import 'package:front_end/src/api_unstable/dart2js.dart' as fe;
-import 'src/compiler.dart';
+import 'src/compiler.dart' show Compiler;
import 'src/options.dart' show CompilerOptions;
// Unless explicitly allowed, passing [:null:] for any argument to the
diff --git a/pkg/compiler/lib/src/common/elements.dart b/pkg/compiler/lib/src/common/elements.dart
index 6aedcca..2919892 100644
--- a/pkg/compiler/lib/src/common/elements.dart
+++ b/pkg/compiler/lib/src/common/elements.dart
@@ -247,7 +247,7 @@
LibraryEntity get foreignLibrary =>
_foreignLibrary ??= _env.lookupLibrary(Uris.dart__foreign_helper);
- /// The dart:_rti library.
+ /// The dart:_internal library.
LibraryEntity get rtiLibrary =>
_rtiLibrary ??= _env.lookupLibrary(Uris.dart__rti, required: true);
@@ -926,24 +926,9 @@
FunctionEntity get defineProperty => _findHelperFunction('defineProperty');
- FunctionEntity get throwLateFieldNI =>
- _findLateHelperFunction('throwLateFieldNI');
-
- FunctionEntity get throwLateFieldAI =>
- _findLateHelperFunction('throwLateFieldAI');
-
FunctionEntity get throwLateFieldADI =>
_findLateHelperFunction('throwLateFieldADI');
- FunctionEntity get throwUnnamedLateFieldNI =>
- _findLateHelperFunction('throwUnnamedLateFieldNI');
-
- FunctionEntity get throwUnnamedLateFieldAI =>
- _findLateHelperFunction('throwUnnamedLateFieldAI');
-
- FunctionEntity get throwUnnamedLateFieldADI =>
- _findLateHelperFunction('throwUnnamedLateFieldADI');
-
bool isExtractTypeArguments(FunctionEntity member) {
return member.name == 'extractTypeArguments' &&
member.library == internalLibrary;
@@ -1135,9 +1120,6 @@
/// Most foreign helpers are located in the `dart:_foreign_helper` library.
bool isForeignHelper(MemberEntity member) {
return member.library == foreignLibrary ||
- isLateReadCheck(member) ||
- isLateWriteOnceCheck(member) ||
- isLateInitializeOnceCheck(member) ||
isCreateInvocationMirrorHelper(member);
}
@@ -1157,23 +1139,11 @@
_isTopLevelFunctionNamed('isJsSentinel', member);
/// Returns `true` if [member] is the `_lateReadCheck` function defined in
- /// dart:_late_helper.
+ /// dart:_internal.
bool isLateReadCheck(MemberEntity member) =>
member.library == lateHelperLibrary &&
_isTopLevelFunctionNamed('_lateReadCheck', member);
- /// Returns `true` if [member] is the `_lateWriteOnceCheck` function defined
- /// in dart:_late_helper.
- bool isLateWriteOnceCheck(MemberEntity member) =>
- member.library == lateHelperLibrary &&
- _isTopLevelFunctionNamed('_lateWriteOnceCheck', member);
-
- /// Returns `true` if [member] is the `_lateInitializeOnceCheck` function
- /// defined in dart:_late_helper.
- bool isLateInitializeOnceCheck(MemberEntity member) =>
- member.library == lateHelperLibrary &&
- _isTopLevelFunctionNamed('_lateInitializeOnceCheck', member);
-
/// Returns `true` if [member] is the `createSentinel` function defined in
/// dart:_internal.
bool isCreateSentinel(MemberEntity member) =>
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index fc65993..93ca227 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -246,9 +246,8 @@
/// Dumps a list of unused [ir.Library]'s in the [KernelResult]. This *must*
/// be called before [setMainAndTrimComponent], because that method will
/// discard the unused [ir.Library]s.
- void dumpUnusedLibraries(ir.Component component, List<Uri> libraries) {
- var usedUris = libraries.toSet();
- bool isUnused(ir.Library l) => !usedUris.contains(l.importUri);
+ void dumpUnusedLibraries(ir.Component component, Set<Uri> libraries) {
+ bool isUnused(ir.Library l) => !libraries.contains(l.importUri);
String libraryString(ir.Library library) {
return '${library.importUri}(${library.fileUri})';
}
@@ -270,7 +269,7 @@
/// Trims a component down to only the provided library uris.
ir.Component trimComponent(
- ir.Component component, List<Uri> librariesToInclude) {
+ ir.Component component, Set<Uri> librariesToInclude) {
var irLibraryMap = <Uri, ir.Library>{};
var irLibraries = <ir.Library>[];
for (var library in component.libraries) {
@@ -325,11 +324,8 @@
}
}
- JClosedWorld computeClosedWorld(
- ir.Component component,
- List<ModuleData> moduleData,
- Uri rootLibraryUri,
- Iterable<Uri> libraries) {
+ JClosedWorld computeClosedWorld(ir.Component component, ModuleData moduleData,
+ Uri rootLibraryUri, Iterable<Uri> libraries) {
frontendStrategy.registerLoadedLibraries(component, libraries);
frontendStrategy.registerModuleData(moduleData);
ResolutionEnqueuer resolutionEnqueuer = frontendStrategy
@@ -402,16 +398,31 @@
untrimmedComponentForDumpInfo = component;
}
if (options.cfeOnly) {
+ // [ModuleData] must be deserialized with the full component, i.e.
+ // before trimming.
+ ModuleData moduleData;
+ if (options.modularAnalysisInputs != null) {
+ moduleData = await serializationTask.deserializeModuleData(component);
+ }
+
+ Set<Uri> includedLibraries = output.libraries.toSet();
if (options.fromDill) {
- List<Uri> libraries = output.libraries;
if (options.dumpUnusedLibraries) {
- dumpUnusedLibraries(component, libraries);
+ dumpUnusedLibraries(component, includedLibraries);
}
if (options.entryUri != null) {
- component = trimComponent(component, libraries);
+ component = trimComponent(component, includedLibraries);
}
}
- await serializationTask.serializeComponent(component);
+ if (moduleData == null) {
+ await serializationTask.serializeComponent(component);
+ } else {
+ // Trim [moduleData] down to only the included libraries.
+ moduleData.impactData
+ .removeWhere((uri, _) => !includedLibraries.contains(uri));
+ await serializationTask.serializeModuleData(
+ moduleData, component, includedLibraries);
+ }
}
return output.withNewComponent(component);
} else {
@@ -434,7 +445,7 @@
'runModularAnalysis', () async => modular_analysis.run(input));
}
- Future<List<ModuleData>> produceModuleData(load_kernel.Output output) async {
+ Future<ModuleData> produceModuleData(load_kernel.Output output) async {
ir.Component component = output.component;
if (options.modularMode) {
Set<Uri> moduleLibraries = output.moduleLibraries.toSet();
@@ -444,7 +455,7 @@
serializationTask.serializeModuleData(
moduleData, component, moduleLibraries);
}
- return [moduleData];
+ return moduleData;
} else {
return await serializationTask.deserializeModuleData(component);
}
@@ -530,7 +541,7 @@
}
Future<ClosedWorldAndIndices> produceClosedWorld(
- load_kernel.Output output, List<ModuleData> moduleData) async {
+ load_kernel.Output output, ModuleData moduleData) async {
ir.Component component = output.component;
ClosedWorldAndIndices closedWorldAndIndices;
if (options.readClosedWorldUri == null) {
@@ -626,7 +637,7 @@
// Run modular analysis. This may be null if modular analysis was not
// requested for this pipeline.
- List<ModuleData> moduleData;
+ ModuleData moduleData;
if (options.modularMode || options.hasModularAnalysisInputs) {
moduleData = await produceModuleData(output);
}
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 6c6fd69..099cf5d 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -318,15 +318,13 @@
fail("Cannot use ${Flags.writeModularAnalysis} "
"and write serialized codegen simultaneously.");
}
- if (writeStrategy == WriteStrategy.toKernel) {
- fail("Cannot use ${Flags.writeModularAnalysis} "
- "and run the CFE simultaneously.");
- }
if (argument != Flags.writeModularAnalysis) {
writeModularAnalysisUri =
fe.nativeToUri(extractPath(argument, isDirectory: false));
}
- writeStrategy = WriteStrategy.toModularAnalysis;
+ writeStrategy = writeStrategy == WriteStrategy.toKernel
+ ? WriteStrategy.toKernelWithModularAnalysis
+ : WriteStrategy.toModularAnalysis;
}
void setReadData(String argument) {
@@ -371,10 +369,6 @@
}
void setCfeOnly(String argument) {
- if (writeStrategy == WriteStrategy.toModularAnalysis) {
- fail("Cannot use ${Flags.cfeOnly} "
- "and write serialized modular analysis simultaneously.");
- }
if (writeStrategy == WriteStrategy.toClosedWorld) {
fail("Cannot use ${Flags.cfeOnly} "
"and write serialized closed world simultaneously.");
@@ -387,7 +381,9 @@
fail("Cannot use ${Flags.cfeOnly} "
"and write serialized codegen simultaneously.");
}
- writeStrategy = WriteStrategy.toKernel;
+ writeStrategy = writeStrategy == WriteStrategy.toModularAnalysis
+ ? WriteStrategy.toKernelWithModularAnalysis
+ : WriteStrategy.toKernel;
}
void setReadCodegen(String argument) {
@@ -825,6 +821,12 @@
"and read serialized codegen simultaneously.");
}
break;
+ case WriteStrategy.toKernelWithModularAnalysis:
+ out ??= Uri.base.resolve('out.dill');
+ options.add(Flags.cfeOnly);
+ writeModularAnalysisUri ??= Uri.base.resolve('$out.mdata');
+ options.add('${Flags.writeModularAnalysis}=${writeModularAnalysisUri}');
+ break;
case WriteStrategy.toModularAnalysis:
writeModularAnalysisUri ??= Uri.base.resolve('$out.mdata');
options.add('${Flags.writeModularAnalysis}=${writeModularAnalysisUri}');
@@ -1007,6 +1009,15 @@
String output = fe.relativizeUri(Uri.base, out, Platform.isWindows);
summary += 'compiled to dill: ${output}.';
break;
+ case WriteStrategy.toKernelWithModularAnalysis:
+ processName = 'Compiled';
+ outputName = 'kernel and bytes data';
+ outputSize = outputProvider.totalDataWritten;
+ String output = fe.relativizeUri(Uri.base, out, Platform.isWindows);
+ String dataOutput = fe.relativizeUri(
+ Uri.base, writeModularAnalysisUri, Platform.isWindows);
+ summary += 'compiled to dill and data: ${output} and ${dataOutput}.';
+ break;
case WriteStrategy.toModularAnalysis:
processName = 'Serialized';
outputName = 'bytes data';
@@ -1547,6 +1558,7 @@
enum WriteStrategy {
toKernel,
+ toKernelWithModularAnalysis,
toModularAnalysis,
toClosedWorld,
toData,
diff --git a/pkg/compiler/lib/src/io/code_output.dart b/pkg/compiler/lib/src/io/code_output.dart
index 19d4300..b603c00 100644
--- a/pkg/compiler/lib/src/io/code_output.dart
+++ b/pkg/compiler/lib/src/io/code_output.dart
@@ -6,7 +6,7 @@
library dart2js.code_output;
-import '../../compiler.dart';
+import '../../compiler.dart' as api show OutputSink;
import 'code_output_listener.dart';
export 'code_output_listener.dart';
import 'source_information.dart';
@@ -223,7 +223,7 @@
class StreamCodeOutput extends AbstractCodeOutput {
@override
int length = 0;
- final OutputSink output;
+ final api.OutputSink output;
StreamCodeOutput(this.output, [List<CodeOutputListener> listeners])
: super(listeners);
diff --git a/pkg/compiler/lib/src/io/source_file.dart b/pkg/compiler/lib/src/io/source_file.dart
index be4708b..961127c 100644
--- a/pkg/compiler/lib/src/io/source_file.dart
+++ b/pkg/compiler/lib/src/io/source_file.dart
@@ -13,7 +13,7 @@
import 'package:kernel/ast.dart' as kernel show Location, Source;
import 'location_provider.dart' show LocationProvider;
-import '../../compiler.dart';
+import '../../compiler.dart' show Input, InputKind;
/// Represents a file of source code. The content can be either a [String] or
/// a UTF-8 encoded [List<int>] of bytes.
diff --git a/pkg/compiler/lib/src/ir/modular.dart b/pkg/compiler/lib/src/ir/modular.dart
index a5da488..5487173 100644
--- a/pkg/compiler/lib/src/ir/modular.dart
+++ b/pkg/compiler/lib/src/ir/modular.dart
@@ -46,27 +46,45 @@
ir.Member node, EnumSet<PragmaAnnotation> pragmaAnnotations);
}
-/// Data computed for an entire compilation module.
+/// [ModuleData] is the data computed modularly, i.e. modularly computed impact
+/// data. Currently, we aggregate this data when computing the closed world, so it
+/// reflects all of the modularly computed data across the entire program.
class ModuleData {
static const String tag = 'ModuleData';
// TODO(joshualitt) Support serializing ModularMemberData;
- final Map<ir.Member, ImpactBuilderData> impactData;
+ final Map<Uri, Map<ir.Member, ImpactBuilderData>> impactData;
- ModuleData(this.impactData);
+ ModuleData([Map<Uri, Map<ir.Member, ImpactBuilderData>> impactData])
+ : this.impactData = impactData ?? {};
- factory ModuleData.fromDataSource(DataSourceReader source) {
+ factory ModuleData.fromImpactData(
+ Map<Uri, Map<ir.Member, ImpactBuilderData>> impactData) =>
+ ModuleData(impactData);
+
+ ModuleData readMoreFromDataSource(DataSourceReader source) {
source.begin(tag);
- var impactData = source
- .readMemberNodeMap(() => ImpactBuilderData.fromDataSource(source));
+ int uriCount = source.readInt();
+ for (int i = 0; i < uriCount; i++) {
+ Uri uri = source.readUri();
+ impactData[uri] = source
+ .readMemberNodeMap(() => ImpactBuilderData.fromDataSource(source));
+ }
source.end(tag);
- return ModuleData(impactData);
+ return this;
}
+ factory ModuleData.fromDataSource(DataSourceReader source) =>
+ ModuleData().readMoreFromDataSource(source);
+
void toDataSink(DataSinkWriter sink) {
sink.begin(tag);
- sink.writeMemberNodeMap<ImpactBuilderData>(
- impactData, (e) => e.toDataSink(sink));
+ sink.writeInt(impactData.keys.length);
+ impactData.forEach((uri, data) {
+ sink.writeUri(uri);
+ sink.writeMemberNodeMap<ImpactBuilderData>(
+ data, (e) => e.toDataSink(sink));
+ });
sink.end(tag);
}
}
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index f6dfa17..37855c0 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -779,28 +779,4 @@
], otherImpacts: [
_needsString('Needed to encode the new RTI ruleset.')
]);
-
- BackendImpact _lateFieldReadCheck;
-
- BackendImpact get lateFieldReadCheck =>
- _lateFieldReadCheck ??= BackendImpact(globalUses: [
- _commonElements.throwUnnamedLateFieldNI,
- _commonElements.throwLateFieldNI,
- ]);
-
- BackendImpact _lateFieldWriteOnceCheck;
-
- BackendImpact get lateFieldWriteOnceCheck =>
- _lateFieldWriteOnceCheck ??= BackendImpact(globalUses: [
- _commonElements.throwUnnamedLateFieldAI,
- _commonElements.throwLateFieldAI,
- ]);
-
- BackendImpact _lateFieldInitializeOnceCheck;
-
- BackendImpact get lateFieldInitializeOnceCheck =>
- _lateFieldInitializeOnceCheck ??= BackendImpact(globalUses: [
- _commonElements.throwUnnamedLateFieldADI,
- _commonElements.throwLateFieldADI,
- ]);
}
diff --git a/pkg/compiler/lib/src/js_backend/frequency_assignment.dart b/pkg/compiler/lib/src/js_backend/frequency_assignment.dart
index a145c9b..d01096c 100644
--- a/pkg/compiler/lib/src/js_backend/frequency_assignment.dart
+++ b/pkg/compiler/lib/src/js_backend/frequency_assignment.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.10
-
import 'dart:collection' show SplayTreeMap;
/// Assigns names from [nameSequence] to items using a naive algorithm.
@@ -63,7 +61,7 @@
List<_Pool> pools = _Pool.makePools(names);
// First cohort with unassigned items.
- _Cohort firstCohort = _Cohort.makeCohorts(items, countOf);
+ _Cohort? firstCohort = _Cohort.makeCohorts(items, countOf);
for (var pool in pools) {
// Completely allocate smaller pools before allocating larger
@@ -125,7 +123,7 @@
/// A [_Pool] is a set of identifiers of the same length from which names are
/// allocated.
class _Pool {
- final List<String /*?*/ > _names = [];
+ final List<String?> _names = [];
// Keep the unused (available) slots in an ordered set for efficiently finding
// the next available slot (i.e. linear rehash). We are concerned about
@@ -164,8 +162,7 @@
(throw StateError('No entries left in pool'));
String allocate(int slot) {
- String name = _names[slot];
- assert(name != null);
+ String name = _names[slot]!;
_names[slot] = null;
_availableSlots.remove(slot);
return name;
@@ -178,23 +175,23 @@
/// A [_Cohort] is a set of entities which occur with the same frequency. The
/// entities are identified by integers.
class _Cohort {
- _Cohort next; // Next cohort in decreasing frequency.
+ _Cohort? next; // Next cohort in decreasing frequency.
final int count; // This is the cohort of items occuring [count] times.
Set<int> unassigned = Set();
_Cohort(this.count);
- _Cohort skipEmpty() {
- _Cohort cohort = this;
+ _Cohort? skipEmpty() {
+ _Cohort? cohort = this;
while (cohort != null && cohort.remaining == 0) cohort = cohort.next;
return cohort;
}
int get remaining => unassigned.length;
- static _Cohort makeCohorts(int items, int Function(int) countOf) {
+ static _Cohort? makeCohorts(int items, int Function(int) countOf) {
// Build _Cohorts.
- _Cohort first, current;
+ _Cohort? first, current;
int lastCount = -1;
for (int item = 0; item < items; item++) {
int count = countOf(item);
@@ -208,7 +205,7 @@
}
current = next;
}
- current.unassigned.add(item);
+ current!.unassigned.add(item);
}
return first;
}
diff --git a/pkg/compiler/lib/src/js_backend/name_sequence.dart b/pkg/compiler/lib/src/js_backend/name_sequence.dart
index 5f97bc8..1f7bdf1 100644
--- a/pkg/compiler/lib/src/js_backend/name_sequence.dart
+++ b/pkg/compiler/lib/src/js_backend/name_sequence.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.10
-
import 'package:front_end/src/api_unstable/dart2js.dart'
show $0, $9, $A, $Z, $_, $a, $z;
diff --git a/pkg/compiler/lib/src/js_backend/resolution_listener.dart b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
index c6b8b41..88e96d3 100644
--- a/pkg/compiler/lib/src/js_backend/resolution_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
@@ -292,19 +292,6 @@
_registerBackendImpact(worldImpact, _impacts.noSuchMethodSupport);
}
- if (_commonElements.isLateReadCheck(member)) {
- _registerBackendImpact(worldImpact, _impacts.lateFieldReadCheck);
- }
-
- if (_commonElements.isLateWriteOnceCheck(member)) {
- _registerBackendImpact(worldImpact, _impacts.lateFieldWriteOnceCheck);
- }
-
- if (_commonElements.isLateInitializeOnceCheck(member)) {
- _registerBackendImpact(
- worldImpact, _impacts.lateFieldInitializeOnceCheck);
- }
-
if (member.isGetter && member.name == Identifiers.runtimeType_) {
// Enable runtime type support if we discover a getter called
// runtimeType. We have to enable runtime type before hitting the
diff --git a/pkg/compiler/lib/src/js_backend/string_abbreviation.dart b/pkg/compiler/lib/src/js_backend/string_abbreviation.dart
index b41e069..391bf6a 100644
--- a/pkg/compiler/lib/src/js_backend/string_abbreviation.dart
+++ b/pkg/compiler/lib/src/js_backend/string_abbreviation.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.10
-
import 'package:front_end/src/api_unstable/dart2js.dart'
show $0, $9, $A, $Z, $a, $z;
@@ -21,7 +19,7 @@
class _Node {
final String string;
- String assignment;
+ late String assignment;
_Node(this.string);
}
@@ -47,7 +45,7 @@
// Partition on the code unit at position [index], setting [terminating] if
// some string ends at this length;
Map<int, List<_Node>> partition = {};
- _Node terminating;
+ _Node? terminating;
for (final node in nodes) {
String string = node.string;
@@ -71,8 +69,8 @@
var keys = partition.keys.toList();
var keyEncodings = _discriminators(keys, path.isEmpty);
for (int key in keys) {
- var children = partition[key];
- var discriminator = keyEncodings[key];
+ var children = partition[key]!;
+ var discriminator = keyEncodings[key]!;
_partition(children, minLength, [...path, discriminator], index + 1);
}
return;
diff --git a/pkg/compiler/lib/src/js_emitter/headers.dart b/pkg/compiler/lib/src/js_emitter/headers.dart
index 66df30c..90e4098 100644
--- a/pkg/compiler/lib/src/js_emitter/headers.dart
+++ b/pkg/compiler/lib/src/js_emitter/headers.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.10
-
library dart2js.js_emitter.headers;
import '../options.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/sorter.dart b/pkg/compiler/lib/src/js_emitter/sorter.dart
index fa27579..0de3e33 100644
--- a/pkg/compiler/lib/src/js_emitter/sorter.dart
+++ b/pkg/compiler/lib/src/js_emitter/sorter.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.10
-
library dart2js.js_emitter.sorter;
import '../elements/entities.dart';
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index 9d05fc1..9430808 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -235,6 +235,14 @@
const Dart2jsDartLibrarySupport();
}
+const implicitlyUsedLibraries = <String>[
+ 'dart:_foreign_helper',
+ 'dart:_interceptors',
+ 'dart:_js_helper',
+ 'dart:_late_helper',
+ 'dart:js_util'
+];
+
// TODO(sigmund): this "extraRequiredLibraries" needs to be removed...
// compile-platform should just specify which libraries to compile instead.
const requiredLibraries = <String, List<String>>{
diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
index 94f87ab..cd1467f 100644
--- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
@@ -229,7 +229,7 @@
}
}
- void registerModuleData(List<ModuleData> data) {
+ void registerModuleData(ModuleData data) {
if (data == null) {
_modularStrategy = KernelModularStrategy(_compilerTask, _elementMap);
} else {
@@ -452,9 +452,10 @@
final Map<ir.Member, ImpactBuilderData> _cache = {};
DeserializedModularStrategy(
- this._compilerTask, this._elementMap, List<ModuleData> data) {
- for (var module in data) {
- _cache.addAll(module.impactData);
+ this._compilerTask, this._elementMap, ModuleData data) {
+ for (Map<ir.Member, ImpactBuilderData> moduleData
+ in data.impactData.values) {
+ _cache.addAll(moduleData);
}
}
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index e899bd1..ab584e3 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -208,7 +208,7 @@
Uri? writeModularAnalysisUri;
/// Helper to determine if compiler is being run just for modular analysis.
- bool get modularMode => writeModularAnalysisUri != null;
+ bool get modularMode => writeModularAnalysisUri != null && !cfeOnly;
List<Uri>? modularAnalysisInputs;
diff --git a/pkg/compiler/lib/src/phase/load_kernel.dart b/pkg/compiler/lib/src/phase/load_kernel.dart
index 57d15e7..f654265 100644
--- a/pkg/compiler/lib/src/phase/load_kernel.dart
+++ b/pkg/compiler/lib/src/phase/load_kernel.dart
@@ -18,7 +18,8 @@
import '../commandline_options.dart';
import '../common.dart';
import '../kernel/front_end_adapter.dart';
-import '../kernel/dart2js_target.dart' show Dart2jsTarget;
+import '../kernel/dart2js_target.dart'
+ show Dart2jsTarget, implicitlyUsedLibraries;
import '../kernel/transformations/clone_mixin_methods_with_super.dart'
as transformMixins show transformLibraries;
import '../options.dart';
@@ -164,9 +165,11 @@
_inferNullSafetyMode(options, isStrongDill);
_validateNullSafetyMode(options);
- // Modular compiles do not include the platform on the input dill
- // either.
- if (options.platformBinaries != null) {
+ // When compiling modularly, a dill for the SDK will be provided. In those
+ // cases we ignore the implicit platform binary.
+ bool platformBinariesIncluded =
+ options.modularMode || options.hasModularAnalysisInputs;
+ if (options.platformBinaries != null && !platformBinariesIncluded) {
var platformUri = options.platformBinaries
.resolve(_getPlatformFilename(options, targetName));
// Modular analysis can be run on the sdk by providing directly the
@@ -331,11 +334,20 @@
search(root);
- // Libraries dependencies do not show implicit imports to `dart:core`.
- var dartCore = component.libraries.firstWhere((lib) {
- return lib.importUri.isScheme('dart') && lib.importUri.path == 'core';
- });
- search(dartCore);
+ // Libraries dependencies do not show implicit imports to certain internal
+ // libraries.
+ const Set<String> alwaysInclude = {
+ 'dart:_internal',
+ 'dart:core',
+ 'dart:async',
+ ...implicitlyUsedLibraries,
+ };
+ for (String uri in alwaysInclude) {
+ Library library = component.libraries.firstWhere((lib) {
+ return '${lib.importUri}' == uri;
+ });
+ search(library);
+ }
libraries = libraries.where(seen.contains);
}
diff --git a/pkg/compiler/lib/src/phase/modular_analysis.dart b/pkg/compiler/lib/src/phase/modular_analysis.dart
index 748e97c..a1cf19a 100644
--- a/pkg/compiler/lib/src/phase/modular_analysis.dart
+++ b/pkg/compiler/lib/src/phase/modular_analysis.dart
@@ -53,12 +53,12 @@
return elementMap;
}
-ModuleData run(Input input) {
- final options = input.options;
- final reporter = input.reporter;
- final elementMap = _createElementMap(
- options, reporter, input.environment, input.component, input.libraries);
- final result = <ir.Member, ImpactBuilderData>{};
+Map<ir.Member, ImpactBuilderData> _computeForLibrary(
+ CompilerOptions options,
+ DiagnosticReporter reporter,
+ KernelToElementMap elementMap,
+ ir.Library library) {
+ Map<ir.Member, ImpactBuilderData> result = {};
void computeForMember(ir.Member member) {
final scopeModel = ScopeModel.from(member, elementMap.constantEvaluator);
final annotations = processMemberAnnotations(
@@ -68,12 +68,23 @@
.impactBuilderData;
}
+ library.members.forEach(computeForMember);
+ for (final cls in library.classes) {
+ cls.members.forEach(computeForMember);
+ }
+ return result;
+}
+
+ModuleData run(Input input) {
+ final options = input.options;
+ final reporter = input.reporter;
+ final elementMap = _createElementMap(
+ options, reporter, input.environment, input.component, input.libraries);
+ Map<Uri, Map<ir.Member, ImpactBuilderData>> result = {};
for (final library in input.component.libraries) {
if (!input.moduleLibraries.contains(library.importUri)) continue;
- library.members.forEach(computeForMember);
- for (final cls in library.classes) {
- cls.members.forEach(computeForMember);
- }
+ result[library.importUri] =
+ _computeForLibrary(options, reporter, elementMap, library);
}
- return ModuleData(result);
+ return ModuleData.fromImpactData(result);
}
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index 9c39ef3..6e5f7df 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -198,7 +198,6 @@
// DataSource source = new ObjectSource(encoding, useDataKinds: true);
// source.registerComponentLookup(new ComponentLookup(component));
// ModuleData.fromDataSource(source);
-
BytesSink bytes = BytesSink();
DataSinkWriter binarySink =
DataSinkWriter(BinaryDataSink(bytes), useDataKinds: true);
@@ -211,17 +210,17 @@
}
}
- Future<List<ModuleData>> deserializeModuleData(ir.Component component) async {
+ Future<ModuleData> deserializeModuleData(ir.Component component) async {
return await measureIoSubtask('deserialize module data', () async {
_reporter.log('Reading data from ${_options.modularAnalysisInputs}');
- List<ModuleData> results = [];
+ final results = ModuleData();
for (Uri uri in _options.modularAnalysisInputs) {
api.Input<List<int>> dataInput =
await _provider.readFromUri(uri, inputKind: api.InputKind.binary);
DataSourceReader source =
DataSourceReader(BinaryDataSource(dataInput.data));
source.registerComponentLookup(ComponentLookup(component));
- results.add(ModuleData.fromDataSource(source));
+ results.readMoreFromDataSource(source);
}
return results;
});
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 02d707c..c34f02f 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -4212,12 +4212,6 @@
_handleForeignCreateJsSentinel(invocation);
} else if (name == 'isJsSentinel') {
_handleForeignIsJsSentinel(invocation);
- } else if (name == '_lateReadCheck') {
- _handleLateReadCheck(invocation);
- } else if (name == '_lateWriteOnceCheck') {
- _handleLateWriteOnceCheck(invocation);
- } else if (name == '_lateInitializeOnceCheck') {
- _handleLateInitializeOnceCheck(invocation);
} else {
reporter.internalError(
_elementMap.getSpannable(targetElement, invocation),
@@ -4907,14 +4901,6 @@
}
void _handleForeignCreateJsSentinel(ir.StaticInvocation invocation) {
- if (_unexpectedForeignArguments(invocation,
- minPositional: 0, maxPositional: 0, typeArgumentCount: 1)) {
- stack.add(
- // Result expected on stack.
- graph.addConstantNull(closedWorld));
- return;
- }
-
SourceInformation sourceInformation =
_sourceInformationBuilder.buildCall(invocation, invocation);
stack.add(graph.addConstantLateSentinel(closedWorld,
@@ -4922,14 +4908,6 @@
}
void _handleForeignIsJsSentinel(ir.StaticInvocation invocation) {
- if (_unexpectedForeignArguments(invocation,
- minPositional: 1, maxPositional: 1)) {
- stack.add(
- // Result expected on stack.
- graph.addConstantNull(closedWorld));
- return;
- }
-
SourceInformation sourceInformation =
_sourceInformationBuilder.buildCall(invocation, invocation);
HInstruction checkedExpression =
@@ -4938,72 +4916,6 @@
..sourceInformation = sourceInformation);
}
- // TODO(fishythefish): Support specialization of late sentinels based on type.
-
- void _handleLateReadCheck(ir.StaticInvocation invocation) {
- if (_unexpectedForeignArguments(invocation,
- minPositional: 2, maxPositional: 2, typeArgumentCount: 1)) {
- stack.add(
- // Result expected on stack.
- graph.addConstantNull(closedWorld));
- return;
- }
-
- SourceInformation sourceInformation =
- _sourceInformationBuilder.buildCall(invocation, invocation);
-
- List<HInstruction> arguments =
- _visitPositionalArguments(invocation.arguments);
- HInstruction value = arguments[0];
- HInstruction name = options.omitLateNames ? null : arguments[1];
-
- push(HLateReadCheck(value, name,
- _abstractValueDomain.excludeLateSentinel(value.instructionType))
- ..sourceInformation = sourceInformation);
- }
-
- void _handleLateWriteOnceCheck(ir.StaticInvocation invocation) {
- if (_unexpectedForeignArguments(invocation,
- minPositional: 2, maxPositional: 2)) {
- stack.add(
- // Result expected on stack.
- graph.addConstantNull(closedWorld));
- return;
- }
-
- SourceInformation sourceInformation =
- _sourceInformationBuilder.buildCall(invocation, invocation);
-
- List<HInstruction> arguments =
- _visitPositionalArguments(invocation.arguments);
- HInstruction value = arguments[0];
- HInstruction name = options.omitLateNames ? null : arguments[1];
-
- push(HLateWriteOnceCheck(value, name, _abstractValueDomain.dynamicType)
- ..sourceInformation = sourceInformation);
- }
-
- void _handleLateInitializeOnceCheck(ir.StaticInvocation invocation) {
- if (_unexpectedForeignArguments(invocation,
- minPositional: 2, maxPositional: 2)) {
- stack.add(
- // Result expected on stack.
- graph.addConstantNull(closedWorld));
- return;
- }
-
- SourceInformation sourceInformation =
- _sourceInformationBuilder.buildCall(invocation, invocation);
-
- List<HInstruction> arguments =
- _visitPositionalArguments(invocation.arguments);
- HInstruction value = arguments[0];
- HInstruction name = options.omitLateNames ? null : arguments[1];
-
- push(HLateInitializeOnceCheck(value, name, _abstractValueDomain.dynamicType)
- ..sourceInformation = sourceInformation);
- }
-
void _pushStaticInvocation(MemberEntity target, List<HInstruction> arguments,
AbstractValue typeMask, List<DartType> typeArguments,
{SourceInformation sourceInformation, InterfaceType instanceType}) {
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index c394f07..dbdf302 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -729,8 +729,7 @@
instruction is HAsCheck ||
instruction is HAsCheckSimple ||
instruction is HBoolConversion ||
- instruction is HNullCheck ||
- instruction is HLateReadCheck) {
+ instruction is HNullCheck) {
String inputName = variableNames.getName(instruction.checkedInput);
if (variableNames.getName(instruction) == inputName) {
needsAssignment = false;
@@ -3018,94 +3017,6 @@
}
@override
- void visitLateReadCheck(HLateReadCheck node) {
- // We generate code roughly equivalent to invoking:
- //
- // T _lateReadCheck<T>(T value, String name) {
- // if (isSentinel(value)) throw LateError.fieldNI(name);
- // return value;
- // }
-
- assert(!node.isRedundant(_closedWorld));
-
- final sourceInformation = node.sourceInformation;
-
- _emitIsLateSentinel(node.checkedInput, sourceInformation);
- final condition = pop();
-
- if (node.hasName) {
- use(node.name);
- _pushCallStatic(
- _commonElements.throwLateFieldNI, [pop()], sourceInformation);
- } else {
- _pushCallStatic(
- _commonElements.throwUnnamedLateFieldNI, const [], sourceInformation);
- }
-
- final lateError =
- pop().toStatement().withSourceInformation(sourceInformation);
- pushStatement(js.If.noElse(condition, lateError)
- .withSourceInformation(sourceInformation));
- }
-
- @override
- void visitLateWriteOnceCheck(HLateWriteOnceCheck node) {
- // We generate code roughly equivalent to invoking:
- //
- // void _lateWriteOnceCheck(Object? value, String name) {
- // if (!isSentinel(value)) throw LateError.fieldAI(name);
- // }
-
- assert(!node.isRedundant(_closedWorld));
-
- final sourceInformation = node.sourceInformation;
- _emitIsLateSentinel(node.checkedInput, sourceInformation, inverse: true);
- final condition = pop();
-
- if (node.hasName) {
- use(node.name);
- _pushCallStatic(
- _commonElements.throwLateFieldAI, [pop()], sourceInformation);
- } else {
- _pushCallStatic(
- _commonElements.throwUnnamedLateFieldAI, [], sourceInformation);
- }
- final lateError =
- pop().toStatement().withSourceInformation(sourceInformation);
- pushStatement(js.If.noElse(condition, lateError)
- .withSourceInformation(sourceInformation));
- }
-
- @override
- void visitLateInitializeOnceCheck(HLateInitializeOnceCheck node) {
- // We generate code roughly equivalent to invoking:
- //
- // void _lateInitializeOnceCheck(Object? value, String name) {
- // if (!isSentinel(value)) throw LateError.fieldADI(name);
- // }
-
- assert(!node.isRedundant(_closedWorld));
-
- final sourceInformation = node.sourceInformation;
- _emitIsLateSentinel(node.checkedInput, sourceInformation, inverse: true);
- final condition = pop();
-
- if (node.hasName) {
- use(node.name);
- _pushCallStatic(
- _commonElements.throwLateFieldADI, [pop()], sourceInformation);
- } else {
- _pushCallStatic(
- _commonElements.throwUnnamedLateFieldADI, [], sourceInformation);
- }
-
- final lateError =
- pop().toStatement().withSourceInformation(sourceInformation);
- pushStatement(js.If.noElse(condition, lateError)
- .withSourceInformation(sourceInformation));
- }
-
- @override
void visitTypeKnown(HTypeKnown node) {
// [HTypeKnown] instructions are removed before generating code.
assert(false);
@@ -3388,9 +3299,9 @@
StaticUse.directInvoke(method, selector.callStructure, null));
}
- _emitIsLateSentinel(HInstruction input, SourceInformation sourceInformation,
+ _emitIsLateSentinel(HIsLateSentinel node, SourceInformation sourceInformation,
{inverse = false}) {
- use(input);
+ use(node.inputs[0]);
js.Expression value = pop();
js.Expression sentinel =
_emitter.constantReference(LateSentinelConstantValue());
@@ -3400,5 +3311,5 @@
@override
visitIsLateSentinel(HIsLateSentinel node) =>
- _emitIsLateSentinel(node.inputs.single, node.sourceInformation);
+ _emitIsLateSentinel(node, node.sourceInformation);
}
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
index ca162ab..600cbac 100644
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
@@ -778,19 +778,6 @@
}
@override
- void visitLateReadCheck(HLateReadCheck instruction) {
- // If the checked value is used, the input might still have one use
- // (i.e. this HLateReadCheck), but it cannot be generated at use, since we
- // will rely on non-generate-at-use to assign the value to a variable.
- //
- // However, if the checked value is unused then the input may be generated
- // at use in the check.
- if (instruction.usedBy.isEmpty) {
- visitInstruction(instruction);
- }
- }
-
- @override
void visitTypeKnown(HTypeKnown instruction) {
// [HTypeKnown] instructions are removed before code generation.
assert(false);
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 6e8e464..16ac75c 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -105,9 +105,6 @@
R visitPrimitiveCheck(HPrimitiveCheck node);
R visitBoolConversion(HBoolConversion node);
R visitNullCheck(HNullCheck node);
- R visitLateReadCheck(HLateReadCheck node);
- R visitLateWriteOnceCheck(HLateWriteOnceCheck node);
- R visitLateInitializeOnceCheck(HLateInitializeOnceCheck node);
R visitTypeKnown(HTypeKnown node);
R visitYield(HYield node);
@@ -594,13 +591,6 @@
@override
visitNullCheck(HNullCheck node) => visitCheck(node);
@override
- visitLateReadCheck(HLateReadCheck node) => visitCheck(node);
- @override
- visitLateWriteOnceCheck(HLateWriteOnceCheck node) => visitCheck(node);
- @override
- visitLateInitializeOnceCheck(HLateInitializeOnceCheck node) =>
- visitCheck(node);
- @override
visitPrimitiveCheck(HPrimitiveCheck node) => visitCheck(node);
@override
visitTypeKnown(HTypeKnown node) => visitCheck(node);
@@ -1111,10 +1101,6 @@
static const int STRING_CONCAT_TYPECODE = 59;
static const int STRINGIFY_TYPECODE = 60;
- static const int LATE_READ_CHECK_TYPECODE = 61;
- static const int LATE_WRITE_ONCE_CHECK_TYPECODE = 62;
- static const int LATE_INITIALIZE_ONCE_CHECK_TYPECODE = 63;
-
HInstruction(this.inputs, this.instructionType) {
assert(inputs.every((e) => e != null), "inputs: $inputs");
}
@@ -3691,121 +3677,6 @@
}
}
-/// A check for a late sentinel to determine if a late field may be read from or
-/// written to.
-abstract class HLateCheck extends HCheck {
- final HInstruction name;
-
- HLateCheck(HInstruction input, this.name, AbstractValue type)
- : super([input, if (name != null) name], type);
-
- bool get hasName => name != null;
-
- @override
- bool isControlFlow() => true;
-
- @override
- bool isCodeMotionInvariant() => false;
-}
-
-/// A check that a late field has been initialized and can therefore be read.
-class HLateReadCheck extends HLateCheck {
- HLateReadCheck(HInstruction input, HInstruction name, AbstractValue type)
- : super(input, name, type);
-
- @override
- accept(HVisitor visitor) => visitor.visitLateReadCheck(this);
-
- @override
- int typeCode() => HInstruction.LATE_READ_CHECK_TYPECODE;
-
- @override
- bool typeEquals(HInstruction other) => other is HLateReadCheck;
-
- @override
- bool dataEquals(HLateReadCheck other) => true;
-
- bool isRedundant(JClosedWorld closedWorld) {
- AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
- AbstractValue inputType = checkedInput.instructionType;
- return abstractValueDomain.isLateSentinel(inputType).isDefinitelyFalse;
- }
-
- @override
- String toString() {
- return 'HLateReadCheck($checkedInput)';
- }
-}
-
-/// A check that a late final field has not been initialized yet and can
-/// therefore be written to.
-///
-/// The difference between [HLateWriteOnceCheck] and [HLateInitializeOnceCheck]
-/// is that the latter occurs on writes performed as part of the initializer
-/// expression.
-class HLateWriteOnceCheck extends HLateCheck {
- HLateWriteOnceCheck(HInstruction input, HInstruction name, AbstractValue type)
- : super(input, name, type);
-
- @override
- accept(HVisitor visitor) => visitor.visitLateWriteOnceCheck(this);
-
- @override
- int typeCode() => HInstruction.LATE_WRITE_ONCE_CHECK_TYPECODE;
-
- @override
- bool typeEquals(HInstruction other) => other is HLateWriteOnceCheck;
-
- @override
- bool dataEquals(HLateWriteOnceCheck other) => true;
-
- bool isRedundant(JClosedWorld closedWorld) {
- AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
- AbstractValue inputType = checkedInput.instructionType;
- return abstractValueDomain.isLateSentinel(inputType).isDefinitelyTrue;
- }
-
- @override
- String toString() {
- return 'HLateWriteOnceCheck($checkedInput)';
- }
-}
-
-/// A check that a late final field has not been initialized yet and can
-/// therefore be initialized.
-///
-/// The difference between [HLateWriteOnceCheck] and [HLateInitializeOnceCheck]
-/// is that the latter occurs on writes performed as part of the initializer
-/// expression.
-class HLateInitializeOnceCheck extends HLateCheck {
- HLateInitializeOnceCheck(
- HInstruction input, HInstruction name, AbstractValue type)
- : super(input, name, type);
-
- @override
- accept(HVisitor visitor) => visitor.visitLateInitializeOnceCheck(this);
-
- @override
- int typeCode() => HInstruction.LATE_INITIALIZE_ONCE_CHECK_TYPECODE;
-
- @override
- bool typeEquals(HInstruction other) => other is HLateInitializeOnceCheck;
-
- @override
- bool dataEquals(HLateInitializeOnceCheck other) => true;
-
- bool isRedundant(JClosedWorld closedWorld) {
- AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
- AbstractValue inputType = checkedInput.instructionType;
- return abstractValueDomain.isLateSentinel(inputType).isDefinitelyTrue;
- }
-
- @override
- String toString() {
- return 'HLateInitializeOnceCheck($checkedInput)';
- }
-}
-
/// The [HTypeKnown] instruction marks a value with a refined type.
class HTypeKnown extends HCheck {
AbstractValue knownType;
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 75f9512..81af4d3 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -1399,24 +1399,6 @@
}
@override
- HInstruction visitLateReadCheck(HLateReadCheck node) {
- if (node.isRedundant(_closedWorld)) return node.checkedInput;
- return node;
- }
-
- @override
- HInstruction visitLateWriteOnceCheck(HLateWriteOnceCheck node) {
- if (node.isRedundant(_closedWorld)) return node.checkedInput;
- return node;
- }
-
- @override
- HInstruction visitLateInitializeOnceCheck(HLateInitializeOnceCheck node) {
- if (node.isRedundant(_closedWorld)) return node.checkedInput;
- return node;
- }
-
- @override
HInstruction visitTypeKnown(HTypeKnown node) {
return node.isRedundant(_closedWorld) ? node.checkedInput : node;
}
@@ -3789,8 +3771,6 @@
@override
void visitNullCheck(HNullCheck instruction) {}
@override
- void visitLateReadCheck(HLateReadCheck instruction) {}
- @override
void visitParameterValue(HParameterValue instruction) {}
@override
void visitRelational(HRelational instruction) {}
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index 98f96f1..a47bd34 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -668,27 +668,6 @@
}
@override
- String visitLateReadCheck(HLateReadCheck node) {
- String checkedInput = temporaryId(node.checkedInput);
- String comment = node.hasName ? "(${temporaryId(node.name)})" : "";
- return "LateReadCheck$comment: $checkedInput";
- }
-
- @override
- String visitLateWriteOnceCheck(HLateWriteOnceCheck node) {
- String checkedInput = temporaryId(node.checkedInput);
- String comment = node.hasName ? "(${temporaryId(node.name)})" : "";
- return "LateWriteOnceCheck$comment: $checkedInput";
- }
-
- @override
- String visitLateInitializeOnceCheck(HLateInitializeOnceCheck node) {
- String checkedInput = temporaryId(node.checkedInput);
- String comment = node.hasName ? "(${temporaryId(node.name)})" : "";
- return "LateInitializeOnceCheck$comment: $checkedInput";
- }
-
- @override
String visitTypeKnown(HTypeKnown node) {
assert(node.inputs.length <= 2);
String result =
diff --git a/pkg/compiler/lib/src/ssa/types_propagation.dart b/pkg/compiler/lib/src/ssa/types_propagation.dart
index 1ddc6f2..082183b 100644
--- a/pkg/compiler/lib/src/ssa/types_propagation.dart
+++ b/pkg/compiler/lib/src/ssa/types_propagation.dart
@@ -449,20 +449,6 @@
}
@override
- AbstractValue visitLateReadCheck(HLateReadCheck instruction) {
- HInstruction input = instruction.checkedInput;
- AbstractValue inputType = input.instructionType;
- AbstractValue outputType =
- abstractValueDomain.excludeLateSentinel(inputType);
- if (inputType != outputType) {
- // Replace dominated uses of input with uses of this check so the uses
- // benefit from the stronger type.
- input.replaceAllUsersDominatedBy(instruction.next, instruction);
- }
- return outputType;
- }
-
- @override
AbstractValue visitAsCheck(HAsCheck instruction) {
return _narrowAsCheck(instruction, instruction.checkedInput,
instruction.checkedType.abstractValue);
diff --git a/pkg/compiler/test/codegen/late_field_redundancy_test.dart b/pkg/compiler/test/codegen/late_field_redundancy_test.dart
deleted file mode 100644
index a0ebf05..0000000
--- a/pkg/compiler/test/codegen/late_field_redundancy_test.dart
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2022, 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.
-
-// @dart = 2.10
-
-import 'package:async_helper/async_helper.dart';
-import 'package:expect/expect.dart';
-import '../helpers/compiler_helper.dart';
-
-const String TEST = r"""
-class Foo {
- late int x;
-}
-
-void entry() {
- final foo = Foo();
- foo.x = 42;
- test(foo);
-}
-
-@pragma('dart2js:noInline')
-void test(Foo foo) {
- final a = foo.x;
- final b = foo.x;
- print([a, b]);
-}
-""";
-
-void main() {
- asyncTest(() async {
- await compile(TEST,
- entry: 'entry',
- methodName: 'test',
- disableTypeInference: false,
- disableInlining: false,
- soundNullSafety: true, check: (String generated) {
- RegExp regexp = new RegExp(r'=== \$');
- Expect.equals(1, regexp.allMatches(generated).length);
- });
- });
-}
diff --git a/pkg/compiler/test/codegen/late_field_test.dart b/pkg/compiler/test/codegen/late_field_test.dart
deleted file mode 100644
index fa34ffe..0000000
--- a/pkg/compiler/test/codegen/late_field_test.dart
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2021, 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.
-
-// @dart = 2.10
-
-import 'dart:async';
-import 'package:async_helper/async_helper.dart';
-import '../helpers/compiler_helper.dart';
-
-const String TEST_DIRECT = r"""
-class Foo {
- late int x;
-}
-
-int test() {
- final foo = Foo();
- foo.x = 40;
- return foo.x + 2;
- // present: '42'
- // absent: '+ 2'
- // absent: 'add'
-}
-""";
-
-const String TEST_INDIRECT = r"""
-class Foo {
- late int x;
-}
-
-int entry() {
- final foo = Foo();
- foo.x = 40;
- return test(foo);
-}
-
-@pragma('dart2js:noInline')
-int test(Foo foo) {
- return foo.x + 2;
- // present: '+ 2'
- // absent: 'add'
-}
-""";
-
-Future check(String test, {String entry: 'test'}) {
- return compile(test,
- entry: entry,
- methodName: 'test',
- check: checkerForAbsentPresent(test),
- disableTypeInference: false,
- disableInlining: false,
- soundNullSafety: true);
-}
-
-void main() {
- asyncTest(() async {
- await check(TEST_DIRECT);
- await check(TEST_INDIRECT, entry: 'entry');
- });
-}
diff --git a/pkg/compiler/test/codegen/late_test.dart b/pkg/compiler/test/codegen/late_test.dart
new file mode 100644
index 0000000..af820fb
--- /dev/null
+++ b/pkg/compiler/test/codegen/late_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2021, 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.
+
+// @dart = 2.10
+
+import 'dart:async';
+import 'package:async_helper/async_helper.dart';
+import '../helpers/compiler_helper.dart';
+
+const String TEST = r"""
+class Foo {
+ late int x;
+}
+
+int foo() {
+ final foo = Foo();
+ foo.x = 40;
+ return foo.x + 2;
+ // present: '+ 2'
+ // absent: 'add'
+}
+""";
+
+Future check(String test) {
+ return compile(test,
+ entry: 'foo',
+ check: checkerForAbsentPresent(test),
+ disableTypeInference: false,
+ disableInlining: false,
+ soundNullSafety: true);
+}
+
+void main() {
+ asyncTest(() async {
+ await check(TEST);
+ });
+}
diff --git a/pkg/compiler/test/dump_info/data/marker.options b/pkg/compiler/test/dump_info/data/marker.options
new file mode 100644
index 0000000..620f7d3
--- /dev/null
+++ b/pkg/compiler/test/dump_info/data/marker.options
@@ -0,0 +1,2 @@
+spec=pkg/compiler/test/dump_info/dump_info_test.dart
+
diff --git a/pkg/compiler/test/dump_info/data/members.dart b/pkg/compiler/test/dump_info/data/members.dart
new file mode 100644
index 0000000..11d6982
--- /dev/null
+++ b/pkg/compiler/test/dump_info/data/members.dart
@@ -0,0 +1,245 @@
+class C {
+ /*member: C.value:function=[{
+ "id": "field/memory:sdk/tests/web/native/main.dart::C.value",
+ "kind": "field",
+ "name": "value",
+ "size": 0,
+ "outputUnit": "outputUnit/main",
+ "parent": "class/memory:sdk/tests/web/native/main.dart::C",
+ "children": [],
+ "inferredType": "[exact=Error]",
+ "code": "",
+ "type": "dynamic"
+}]*/
+ final value;
+ /*member: C.counter:function=[{
+ "id": "field/memory:sdk/tests/web/native/main.dart::C.counter",
+ "kind": "field",
+ "name": "counter",
+ "size": 18,
+ "outputUnit": "outputUnit/main",
+ "parent": "class/memory:sdk/tests/web/native/main.dart::C",
+ "children": [],
+ "inferredType": "[subclass=JSPositiveInt]",
+ "code": "$.C_counter = 0;\n",
+ "type": "int"
+}]*/
+ static int counter = 0;
+ /*member: C.y:function=[{
+ "id": "field/memory:sdk/tests/web/native/main.dart::C.y",
+ "kind": "field",
+ "name": "y",
+ "size": 124,
+ "outputUnit": "outputUnit/main",
+ "parent": "class/memory:sdk/tests/web/native/main.dart::C",
+ "children": [],
+ "inferredType": "[null|exact=JSBool]",
+ "code": "_lazy($, \"C_y\", \"$get$C_y\", () => {\n var t1 = $.C_counter + 1;\n $.C_counter = t1;\n return t1 === 4;\n });\n",
+ "type": "bool"
+}]*/
+ static bool y = C.compute();
+ /*member: C.compute:function=[{
+ "id": "function/memory:sdk/tests/web/native/main.dart::C.compute",
+ "kind": "function",
+ "name": "compute",
+ "size": 0,
+ "outputUnit": "outputUnit/main",
+ "parent": "class/memory:sdk/tests/web/native/main.dart::C",
+ "children": [],
+ "modifiers": {
+ "static": true,
+ "const": false,
+ "factory": false,
+ "external": false
+ },
+ "returnType": "bool",
+ "inferredReturnType": "[exact=JSBool]",
+ "parameters": [],
+ "sideEffects": "SideEffects(reads static; writes static)",
+ "inlinedCount": 1,
+ "code": "",
+ "type": "bool Function()"
+}]*/
+ static bool compute() {
+ C.counter += 1;
+ return counter == 4;
+ }
+
+ /*member: C._default:function=[{
+ "id": "function/memory:sdk/tests/web/native/main.dart::C.C._default",
+ "kind": "function",
+ "name": "C._default",
+ "size": 0,
+ "outputUnit": "outputUnit/main",
+ "parent": "class/memory:sdk/tests/web/native/main.dart::C",
+ "children": [],
+ "modifiers": {
+ "static": false,
+ "const": false,
+ "factory": false,
+ "external": false
+ },
+ "returnType": "dynamic",
+ "inferredReturnType": "[exact=C]",
+ "parameters": [
+ {
+ "name": "message",
+ "type": "[exact=Error]",
+ "declaredType": "Object"
+ }
+ ],
+ "sideEffects": "SideEffects(reads nothing; writes nothing)",
+ "inlinedCount": 1,
+ "code": "",
+ "type": "dynamic Function(Object)"
+}]*/
+ C._default(Object message) : value = message;
+
+ /*member: C.create:function=[{
+ "id": "function/memory:sdk/tests/web/native/main.dart::C.C.create",
+ "kind": "function",
+ "name": "C.create",
+ "size": 0,
+ "outputUnit": "outputUnit/main",
+ "parent": "class/memory:sdk/tests/web/native/main.dart::C",
+ "children": [],
+ "modifiers": {
+ "static": false,
+ "const": false,
+ "factory": true,
+ "external": false
+ },
+ "returnType": "C",
+ "inferredReturnType": "[exact=C]",
+ "parameters": [
+ {
+ "name": "object",
+ "type": "[exact=JSUInt31]",
+ "declaredType": "dynamic"
+ }
+ ],
+ "sideEffects": "SideEffects(reads nothing; writes nothing)",
+ "inlinedCount": 1,
+ "code": "",
+ "type": "C Function(dynamic)"
+}]*/
+ factory C.create(object) {
+ return C._default(Error());
+ }
+}
+
+/*member: F:function=[{
+ "id": "function/memory:sdk/tests/web/native/main.dart::F",
+ "kind": "function",
+ "name": "F",
+ "size": 52,
+ "outputUnit": "outputUnit/main",
+ "parent": "library/memory:sdk/tests/web/native/main.dart::",
+ "children": [],
+ "modifiers": {
+ "static": false,
+ "const": false,
+ "factory": false,
+ "external": false
+ },
+ "returnType": "void",
+ "inferredReturnType": "[null]",
+ "parameters": [],
+ "sideEffects": "SideEffects(reads nothing; writes nothing)",
+ "inlinedCount": 0,
+ "code": "F() {\n }\n_static_0(A, \"main__F$closure\", \"F\", 0);\n",
+ "type": "void Function()"
+}]*/
+void F() {}
+
+class B {
+ static void M() {}
+ static const int a = 2123;
+}
+
+class A {
+ /*member: A.a:function=[{
+ "id": "field/memory:sdk/tests/web/native/main.dart::A.a",
+ "kind": "field",
+ "name": "a",
+ "size": 0,
+ "outputUnit": "outputUnit/main",
+ "parent": "class/memory:sdk/tests/web/native/main.dart::A",
+ "children": [],
+ "inferredType": "Value([exact=JSString], value: \"hello\")",
+ "code": "",
+ "type": "dynamic"
+}]*/
+ final a;
+
+/*member: A.:function=[{
+ "id": "function/memory:sdk/tests/web/native/main.dart::A.A",
+ "kind": "function",
+ "name": "A",
+ "size": 0,
+ "outputUnit": "outputUnit/main",
+ "parent": "class/memory:sdk/tests/web/native/main.dart::A",
+ "children": [],
+ "modifiers": {
+ "static": false,
+ "const": true,
+ "factory": false,
+ "external": false
+ },
+ "returnType": "dynamic",
+ "inferredReturnType": "[exact=A]",
+ "parameters": [],
+ "sideEffects": "SideEffects(reads nothing; writes nothing)",
+ "inlinedCount": 1,
+ "code": "",
+ "type": "dynamic Function()"
+}]*/
+ const A() : a = "hello";
+}
+
+/*member: constList:function=[{
+ "id": "field/memory:sdk/tests/web/native/main.dart::constList",
+ "kind": "field",
+ "name": "constList",
+ "size": 0,
+ "outputUnit": "outputUnit/main",
+ "parent": "library/memory:sdk/tests/web/native/main.dart::",
+ "children": [],
+ "inferredType": "Container([exact=JSUnmodifiableArray], element: [exact=A], length: 1)",
+ "code": "",
+ "type": "List<A>"
+}]*/
+final constList = const [
+ const A(),
+];
+
+/*member: main:function=[{
+ "id": "function/memory:sdk/tests/web/native/main.dart::main",
+ "kind": "function",
+ "name": "main",
+ "size": 199,
+ "outputUnit": "outputUnit/main",
+ "parent": "library/memory:sdk/tests/web/native/main.dart::",
+ "children": [],
+ "modifiers": {
+ "static": false,
+ "const": false,
+ "factory": false,
+ "external": false
+ },
+ "returnType": "dynamic",
+ "inferredReturnType": "[null]",
+ "parameters": [],
+ "sideEffects": "SideEffects(reads anything; writes anything)",
+ "inlinedCount": 0,
+ "code": "main() {\n null.add$1(0, [B.List_A, B.C_A, 2123, 2133, A.main__F$closure(), $.$get$C_y(), \"hello\"]);\n null.add$1(0, B.C_A);\n null.add$1(0, new A.C());\n A.printString(\"null\");\n }",
+ "type": "dynamic Function()"
+}]*/
+main() {
+ dynamic l = [constList, const A(), B.a, B.a + 10, F, C.y, A().a];
+ dynamic r;
+ r.add(l);
+ r.add(const A());
+ r.add(C.create(10));
+ print(r);
+}
diff --git a/pkg/compiler/test/dump_info/dump_info_test.dart b/pkg/compiler/test/dump_info/dump_info_test.dart
new file mode 100644
index 0000000..8410f9b
--- /dev/null
+++ b/pkg/compiler/test/dump_info/dump_info_test.dart
@@ -0,0 +1,189 @@
+// Copyright (c) 2022, 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.
+
+// @dart = 2.7
+
+import 'dart:convert';
+import 'dart:io';
+import 'package:_fe_analyzer_shared/src/testing/features.dart';
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/dump_info.dart';
+import 'package:compiler/src/elements/entities.dart';
+import 'package:compiler/src/js_model/element_map.dart';
+import 'package:compiler/src/js_model/js_world.dart';
+import 'package:dart2js_info/info.dart' as info;
+import 'package:dart2js_info/json_info_codec.dart' as info;
+import 'package:kernel/ast.dart' as ir;
+import '../equivalence/id_equivalence.dart';
+import '../equivalence/id_equivalence_helper.dart';
+
+main(List<String> args) {
+ asyncTest(() async {
+ Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
+ print('Testing output of dump-info');
+ print('==================================================================');
+ await checkTests(dataDir, const DumpInfoDataComputer(),
+ args: args, testedConfigs: allSpecConfigs, options: ['--dump-info']);
+ });
+}
+
+class Tags {
+ static const String library = 'library';
+ static const String clazz = 'class';
+ static const String classType = 'classType';
+ static const String function = 'function';
+ static const String typeDef = 'typedef';
+ static const String field = 'field';
+ static const String constant = 'constant';
+ static const String holding = 'holding';
+ static const String dependencies = 'dependencies';
+ static const String outputUnits = 'outputUnits';
+ static const String deferredFiles = 'deferredFiles';
+}
+
+class DumpInfoDataComputer extends DataComputer<Features> {
+ const DumpInfoDataComputer();
+
+ static const String wildcard = '%';
+
+ @override
+ void computeMemberData(Compiler compiler, MemberEntity member,
+ Map<Id, ActualData<Features>> actualMap,
+ {bool verbose: false}) {
+ JsonEncoder encoder = const JsonEncoder.withIndent(' ');
+ var converter = info.AllInfoToJsonConverter(
+ isBackwardCompatible: true, filterTreeshaken: false);
+ DumpInfoStateData dumpInfoState = compiler.dumpInfoStateForTesting;
+
+ Features features = new Features();
+ var functionInfo = dumpInfoState.entityToInfo[member];
+ if (functionInfo == null) return;
+
+ if (functionInfo is info.FunctionInfo) {
+ features.addElement(
+ Tags.function, encoder.convert(functionInfo.accept(converter)));
+ }
+
+ if (functionInfo is info.FieldInfo) {
+ features.addElement(
+ Tags.function, encoder.convert(functionInfo.accept(converter)));
+ }
+
+ JsClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
+ JsToElementMap elementMap = closedWorld.elementMap;
+ ir.Member node = elementMap.getMemberDefinition(member).node;
+ Id id = computeMemberId(node);
+ ir.TreeNode nodeWithOffset = computeTreeNodeWithOffset(node);
+ actualMap[id] = new ActualData<Features>(id, features,
+ nodeWithOffset?.location?.file, nodeWithOffset?.fileOffset, member);
+ }
+
+ @override
+ DataInterpreter<Features> get dataValidator =>
+ const JsonFeaturesDataInterpreter(wildcard: wildcard);
+}
+
+/// Feature interpreter for Features with Json values.
+///
+/// The data annotation reader removes whitespace, but this fork adds them
+/// back for readability.
+class JsonFeaturesDataInterpreter implements DataInterpreter<Features> {
+ final String wildcard;
+
+ const JsonFeaturesDataInterpreter({this.wildcard});
+
+ @override
+ String isAsExpected(Features actualFeatures, String expectedData) {
+ JsonEncoder encoder = const JsonEncoder.withIndent(' ');
+
+ if (wildcard != null && expectedData == wildcard) {
+ return null;
+ } else if (expectedData == '') {
+ return actualFeatures.isNotEmpty ? "Expected empty data." : null;
+ } else {
+ List<String> errorsFound = [];
+ Features expectedFeatures = Features.fromText(expectedData);
+ Set<String> validatedFeatures = new Set<String>();
+ expectedFeatures.forEach((String key, Object expectedValue) {
+ validatedFeatures.add(key);
+ Object actualValue = actualFeatures[key];
+ if (!actualFeatures.containsKey(key)) {
+ errorsFound.add('No data found for $key');
+ } else if (expectedValue == '') {
+ if (actualValue != '') {
+ errorsFound.add('Non-empty data found for $key');
+ }
+ } else if (wildcard != null && expectedValue == wildcard) {
+ return;
+ } else if (expectedValue is List) {
+ if (actualValue is List) {
+ List actualList = actualValue.toList();
+ for (Object expectedObject in expectedValue) {
+ String expectedText =
+ encoder.convert(jsonDecode('$expectedObject'));
+ bool matchFound = false;
+ if (wildcard != null && expectedText.endsWith(wildcard)) {
+ // Wildcard matcher.
+ String prefix =
+ expectedText.substring(0, expectedText.indexOf(wildcard));
+ List matches = [];
+ for (Object actualObject in actualList) {
+ if ('$actualObject'.startsWith(prefix)) {
+ matches.add(actualObject);
+ matchFound = true;
+ }
+ }
+ for (Object match in matches) {
+ actualList.remove(match);
+ }
+ } else {
+ for (Object actualObject in actualList) {
+ if (expectedText == '$actualObject') {
+ actualList.remove(actualObject);
+ matchFound = true;
+ break;
+ }
+ }
+ }
+ if (!matchFound) {
+ errorsFound.add("No match found for $key=[$expectedText]");
+ }
+ }
+ if (actualList.isNotEmpty) {
+ errorsFound
+ .add("Extra data found $key=[${actualList.join(',')}]");
+ }
+ } else {
+ errorsFound.add("List data expected for $key: "
+ "expected '$expectedValue', found '${actualValue}'");
+ }
+ } else if (expectedValue != actualValue) {
+ errorsFound.add("Mismatch for $key: expected '$expectedValue', "
+ "found '${actualValue}'");
+ }
+ });
+ actualFeatures.forEach((String key, Object value) {
+ if (!validatedFeatures.contains(key)) {
+ if (value == '') {
+ errorsFound.add("Extra data found '$key'");
+ } else {
+ errorsFound.add("Extra data found $key=$value");
+ }
+ }
+ });
+ return errorsFound.isNotEmpty ? errorsFound.join('\n ') : null;
+ }
+ }
+
+ @override
+ String getText(Features actualData, [String indentation]) {
+ return actualData.getText(indentation);
+ }
+
+ @override
+ bool isEmpty(Features actualData) {
+ return actualData == null || actualData.isEmpty;
+ }
+}
diff --git a/pkg/compiler/tool/modular_test_suite.dart b/pkg/compiler/tool/modular_test_suite.dart
index 430c81a..491d6ad 100644
--- a/pkg/compiler/tool/modular_test_suite.dart
+++ b/pkg/compiler/tool/modular_test_suite.dart
@@ -26,9 +26,7 @@
FullDillCompilationStep(onlyOnSdk: true),
ModularAnalysisStep(onlyOnSdk: true),
ModularAnalysisStep(),
- // TODO(joshualitt): Re-enable ConcatenateDillStep after it works
- // correctly alongside modular analysis.
- // ConcatenateDillsStep(useModularAnalysis: true),
+ ConcatenateDillsStep(useModularAnalysis: true),
ComputeClosedWorldStep(useModularAnalysis: true),
GlobalAnalysisStep(),
Dart2jsCodegenStep(codeId0),
diff --git a/pkg/compiler/tool/modular_test_suite_helper.dart b/pkg/compiler/tool/modular_test_suite_helper.dart
index 91525b6..ac95cce 100644
--- a/pkg/compiler/tool/modular_test_suite_helper.dart
+++ b/pkg/compiler/tool/modular_test_suite_helper.dart
@@ -32,6 +32,7 @@
const fullDillId = DataId("concatenate.dill");
const modularUpdatedDillId = DataId("modular.dill");
const modularDataId = DataId("modular.data");
+const modularFullDataId = DataId("concatenate.modular.data");
const closedWorldId = DataId("world");
const globalUpdatedDillId = DataId("global.dill");
const globalDataId = DataId("global.data");
@@ -304,10 +305,16 @@
DataId get idForDill => useModularAnalysis ? modularUpdatedDillId : dillId;
- List<DataId> get dependencies => [idForDill];
+ List<DataId> get dependencies => [
+ idForDill,
+ if (useModularAnalysis) modularDataId,
+ ];
@override
- List<DataId> get resultData => const [fullDillId];
+ List<DataId> get resultData => [
+ fullDillId,
+ if (useModularAnalysis) modularFullDataId,
+ ];
@override
bool get needsSources => false;
@@ -344,6 +351,10 @@
'${Flags.inputDill}=${toUri(module, dillId)}',
for (String flag in flags) '--enable-experiment=$flag',
'${Flags.dillDependencies}=${dillDependencies.join(',')}',
+ if (useModularAnalysis) ...[
+ '${Flags.readModularAnalysis}=${dataDependencies.join(',')}',
+ '${Flags.writeModularAnalysis}=${toUri(module, modularFullDataId)}',
+ ],
'${Flags.cfeOnly}',
'--out=${toUri(module, fullDillId)}',
];
@@ -364,14 +375,11 @@
class ComputeClosedWorldStep extends IOModularStep {
final bool useModularAnalysis;
- DataId get idForDill =>
- useModularAnalysis ? modularUpdatedDillId : fullDillId;
-
ComputeClosedWorldStep({this.useModularAnalysis});
List<DataId> get dependencies => [
- idForDill,
- if (useModularAnalysis) modularDataId,
+ fullDillId,
+ if (useModularAnalysis) modularFullDataId,
];
@override
@@ -394,25 +402,16 @@
List<String> flags) async {
if (_options.verbose)
print("\nstep: dart2js compute closed world on $module");
- Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
- Iterable<String> dillDependencies =
- transitiveDependencies.map((m) => '${toUri(m, idForDill)}');
- List<String> dataDependencies = transitiveDependencies
- .map((m) => '${toUri(m, modularDataId)}')
- .toList();
- dataDependencies.add('${toUri(module, modularDataId)}');
List<String> args = [
'--packages=${sdkRoot.toFilePath()}/$packageConfigJsonPath',
_dart2jsScript,
// TODO(sigmund): remove this dependency on libraries.json
if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot',
'${Flags.entryUri}=$fakeRoot${module.mainSource}',
- '${Flags.inputDill}=${toUri(module, idForDill)}',
+ '${Flags.inputDill}=${toUri(module, fullDillId)}',
for (String flag in flags) '--enable-experiment=$flag',
- if (useModularAnalysis) ...[
- '${Flags.dillDependencies}=${dillDependencies.join(',')}',
- '${Flags.readModularAnalysis}=${dataDependencies.join(',')}',
- ],
+ if (useModularAnalysis)
+ '${Flags.readModularAnalysis}=${toUri(module, modularFullDataId)}',
'${Flags.writeClosedWorld}=${toUri(module, closedWorldId)}',
Flags.noClosedWorldInData,
'--out=${toUri(module, globalUpdatedDillId)}',
diff --git a/pkg/front_end/lib/src/fasta/kernel/macro/identifiers.dart b/pkg/front_end/lib/src/fasta/kernel/macro/identifiers.dart
index 8ca4ce2..1ecd8aa 100644
--- a/pkg/front_end/lib/src/fasta/kernel/macro/identifiers.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/macro/identifiers.dart
@@ -141,14 +141,14 @@
Uri? uri;
String? staticScope;
macro.IdentifierKind kind;
- if (memberBuilder.isStatic || memberBuilder.isConstructor) {
+ if (memberBuilder.isTopLevel) {
+ uri = memberBuilder.libraryBuilder.importUri;
+ kind = macro.IdentifierKind.topLevelMember;
+ } else if (memberBuilder.isStatic || memberBuilder.isConstructor) {
ClassBuilder classBuilder = memberBuilder.classBuilder!;
staticScope = classBuilder.name;
uri = classBuilder.libraryBuilder.importUri;
kind = macro.IdentifierKind.staticInstanceMember;
- } else if (memberBuilder.isTopLevel) {
- uri = memberBuilder.libraryBuilder.importUri;
- kind = macro.IdentifierKind.topLevelMember;
} else {
kind = macro.IdentifierKind.instanceMember;
}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 72cd04e..3ec34d7 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -3595,7 +3595,9 @@
Expression _hoist(Expression expression, DartType type,
List<VariableDeclaration>? hoistedExpressions) {
- if (hoistedExpressions != null && expression is! ThisExpression) {
+ if (hoistedExpressions != null &&
+ expression is! ThisExpression &&
+ expression is! FunctionExpression) {
VariableDeclaration variable = createVariable(expression, type);
hoistedExpressions.add(variable);
return createVariableGet(variable);
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 3d82ad2..dae8e71 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -577,6 +577,10 @@
JsInteropStaticInteropWithInstanceMembers/example: Fail # Web compiler specific
JsInteropStaticInteropWithNonStaticSupertype/analyzerCode: Fail # Web compiler specific
JsInteropStaticInteropWithNonStaticSupertype/example: Fail # Web compiler specific
+JsInteropStaticInteropTrustTypesUsageNotAllowed/analyzerCode: Fail # Web compiler specific
+JsInteropStaticInteropTrustTypesUsageNotAllowed/example: Fail # Web compiler specific
+JsInteropStaticInteropTrustTypesUsedWithoutStaticInterop/analyzerCode: Fail # Web compiler specific
+JsInteropStaticInteropTrustTypesUsedWithoutStaticInterop/example: Fail # Web compiler specific
LanguageVersionInvalidInDotPackages/analyzerCode: Fail
LanguageVersionMismatchInPart/analyzerCode: Fail
LanguageVersionMismatchInPart/part_wrapped_script: Fail # Part in (now) part.
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 2e1aa57..887e231 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -5197,6 +5197,14 @@
problemMessage: "JS interop class '#name' has an `@staticInterop` annotation, but has supertype '#name2', which is non-static."
correctionMessage: "Try marking the supertype as a static interop class using `@staticInterop`."
+JsInteropStaticInteropTrustTypesUsedWithoutStaticInterop:
+ problemMessage: "JS interop class '#name' has an `@trustTypes` annotation, but no `@staticInterop` annotation."
+ correctionMessage: "Try marking the class using `@staticInterop`."
+
+JsInteropStaticInteropTrustTypesUsageNotAllowed:
+ problemMessage: "JS interop class '#name' has an `@trustTypes` annotation, but `@trustTypes` is only supported within the sdk."
+ correctionMessage: "Try removing the `@trustTypes` annotation."
+
DefaultListConstructorError:
problemMessage: "Can't use the default List constructor."
correctionMessage: "Try using List.filled instead."
diff --git a/pkg/front_end/test/spell_checking_list_messages.txt b/pkg/front_end/test/spell_checking_list_messages.txt
index 329dc17..00b69d3 100644
--- a/pkg/front_end/test/spell_checking_list_messages.txt
+++ b/pkg/front_end/test/spell_checking_list_messages.txt
@@ -87,6 +87,7 @@
team
this.namedconstructor
this.x
+trusttypes
type3.#name
u
unsound
diff --git a/pkg/front_end/testcases/extensions/issue40596.dart.weak.expect b/pkg/front_end/testcases/extensions/issue40596.dart.weak.expect
index ca760ff..23c03fe 100644
--- a/pkg/front_end/testcases/extensions/issue40596.dart.weak.expect
+++ b/pkg/front_end/testcases/extensions/issue40596.dart.weak.expect
@@ -11,9 +11,9 @@
}
static method main() → void {
asy::StreamController<core::String> controller = asy::StreamController::•<core::String>();
- let final asy::StreamController<core::String> #t1 = controller in let final (dynamic) → Null #t2 = (dynamic s) → Null {
+ let final asy::StreamController<core::String> #t1 = controller in self::Extension|call<core::String>(#t1.{asy::StreamController::stream}{asy::Stream<core::String>}, (dynamic s) → Null {
core::print(s);
- } in self::Extension|call<core::String>(#t1.{asy::StreamController::stream}{asy::Stream<core::String>}, #t2);
+ });
}
static method Extension|call<T extends core::Object? = dynamic>(lowered final asy::Stream<self::Extension|call::T%> #this, core::Function onData) → asy::StreamSubscription<self::Extension|call::T%> {
return #this.{asy::Stream::listen}((self::Extension|call::T% d) → void {
diff --git a/pkg/front_end/testcases/extensions/issue40596.dart.weak.modular.expect b/pkg/front_end/testcases/extensions/issue40596.dart.weak.modular.expect
index ca760ff..23c03fe 100644
--- a/pkg/front_end/testcases/extensions/issue40596.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/extensions/issue40596.dart.weak.modular.expect
@@ -11,9 +11,9 @@
}
static method main() → void {
asy::StreamController<core::String> controller = asy::StreamController::•<core::String>();
- let final asy::StreamController<core::String> #t1 = controller in let final (dynamic) → Null #t2 = (dynamic s) → Null {
+ let final asy::StreamController<core::String> #t1 = controller in self::Extension|call<core::String>(#t1.{asy::StreamController::stream}{asy::Stream<core::String>}, (dynamic s) → Null {
core::print(s);
- } in self::Extension|call<core::String>(#t1.{asy::StreamController::stream}{asy::Stream<core::String>}, #t2);
+ });
}
static method Extension|call<T extends core::Object? = dynamic>(lowered final asy::Stream<self::Extension|call::T%> #this, core::Function onData) → asy::StreamSubscription<self::Extension|call::T%> {
return #this.{asy::Stream::listen}((self::Extension|call::T% d) → void {
diff --git a/pkg/front_end/testcases/extensions/issue40596.dart.weak.transformed.expect b/pkg/front_end/testcases/extensions/issue40596.dart.weak.transformed.expect
index ca760ff..23c03fe 100644
--- a/pkg/front_end/testcases/extensions/issue40596.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/extensions/issue40596.dart.weak.transformed.expect
@@ -11,9 +11,9 @@
}
static method main() → void {
asy::StreamController<core::String> controller = asy::StreamController::•<core::String>();
- let final asy::StreamController<core::String> #t1 = controller in let final (dynamic) → Null #t2 = (dynamic s) → Null {
+ let final asy::StreamController<core::String> #t1 = controller in self::Extension|call<core::String>(#t1.{asy::StreamController::stream}{asy::Stream<core::String>}, (dynamic s) → Null {
core::print(s);
- } in self::Extension|call<core::String>(#t1.{asy::StreamController::stream}{asy::Stream<core::String>}, #t2);
+ });
}
static method Extension|call<T extends core::Object? = dynamic>(lowered final asy::Stream<self::Extension|call::T%> #this, core::Function onData) → asy::StreamSubscription<self::Extension|call::T%> {
return #this.{asy::Stream::listen}((self::Extension|call::T% d) → void {
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/issue46123.dart.weak.expect b/pkg/front_end/testcases/general/constants/js_semantics/issue46123.dart.weak.expect
index c62f518..d5843e3 100644
--- a/pkg/front_end/testcases/general/constants/js_semantics/issue46123.dart.weak.expect
+++ b/pkg/front_end/testcases/general/constants/js_semantics/issue46123.dart.weak.expect
@@ -35,5 +35,5 @@
Constructor coverage from constants:
org-dartlang-testcase:///issue46123.dart:
-- JS. (from org-dartlang-testcase-sdk:///pkg/js/lib/js.dart:21:9)
+- JS. (from org-dartlang-testcase-sdk:///pkg/js/lib/js.dart:23:9)
- Object. (from org-dartlang-sdk:///lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/issue46123.dart.weak.modular.expect b/pkg/front_end/testcases/general/constants/js_semantics/issue46123.dart.weak.modular.expect
index c62f518..d5843e3 100644
--- a/pkg/front_end/testcases/general/constants/js_semantics/issue46123.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/general/constants/js_semantics/issue46123.dart.weak.modular.expect
@@ -35,5 +35,5 @@
Constructor coverage from constants:
org-dartlang-testcase:///issue46123.dart:
-- JS. (from org-dartlang-testcase-sdk:///pkg/js/lib/js.dart:21:9)
+- JS. (from org-dartlang-testcase-sdk:///pkg/js/lib/js.dart:23:9)
- Object. (from org-dartlang-sdk:///lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/issue46123.dart.weak.transformed.expect b/pkg/front_end/testcases/general/constants/js_semantics/issue46123.dart.weak.transformed.expect
index c62f518..d5843e3 100644
--- a/pkg/front_end/testcases/general/constants/js_semantics/issue46123.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/constants/js_semantics/issue46123.dart.weak.transformed.expect
@@ -35,5 +35,5 @@
Constructor coverage from constants:
org-dartlang-testcase:///issue46123.dart:
-- JS. (from org-dartlang-testcase-sdk:///pkg/js/lib/js.dart:21:9)
+- JS. (from org-dartlang-testcase-sdk:///pkg/js/lib/js.dart:23:9)
- Object. (from org-dartlang-sdk:///lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/issue46123b.dart.weak.expect b/pkg/front_end/testcases/general/constants/js_semantics/issue46123b.dart.weak.expect
index 215e011..5ef5a68 100644
--- a/pkg/front_end/testcases/general/constants/js_semantics/issue46123b.dart.weak.expect
+++ b/pkg/front_end/testcases/general/constants/js_semantics/issue46123b.dart.weak.expect
@@ -37,5 +37,5 @@
Constructor coverage from constants:
org-dartlang-testcase:///issue46123b.dart:
-- JS. (from org-dartlang-testcase-sdk:///pkg/js/lib/js.dart:21:9)
+- JS. (from org-dartlang-testcase-sdk:///pkg/js/lib/js.dart:23:9)
- Object. (from org-dartlang-sdk:///lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/issue46123b.dart.weak.modular.expect b/pkg/front_end/testcases/general/constants/js_semantics/issue46123b.dart.weak.modular.expect
index 215e011..5ef5a68 100644
--- a/pkg/front_end/testcases/general/constants/js_semantics/issue46123b.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/general/constants/js_semantics/issue46123b.dart.weak.modular.expect
@@ -37,5 +37,5 @@
Constructor coverage from constants:
org-dartlang-testcase:///issue46123b.dart:
-- JS. (from org-dartlang-testcase-sdk:///pkg/js/lib/js.dart:21:9)
+- JS. (from org-dartlang-testcase-sdk:///pkg/js/lib/js.dart:23:9)
- Object. (from org-dartlang-sdk:///lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/issue46123b.dart.weak.transformed.expect b/pkg/front_end/testcases/general/constants/js_semantics/issue46123b.dart.weak.transformed.expect
index 215e011..5ef5a68 100644
--- a/pkg/front_end/testcases/general/constants/js_semantics/issue46123b.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/constants/js_semantics/issue46123b.dart.weak.transformed.expect
@@ -37,5 +37,5 @@
Constructor coverage from constants:
org-dartlang-testcase:///issue46123b.dart:
-- JS. (from org-dartlang-testcase-sdk:///pkg/js/lib/js.dart:21:9)
+- JS. (from org-dartlang-testcase-sdk:///pkg/js/lib/js.dart:23:9)
- Object. (from org-dartlang-sdk:///lib/core/object.dart:25:9)
diff --git a/pkg/frontend_server/lib/compute_kernel.dart b/pkg/frontend_server/lib/compute_kernel.dart
index 6e89be6..2c70e9d 100644
--- a/pkg/frontend_server/lib/compute_kernel.dart
+++ b/pkg/frontend_server/lib/compute_kernel.dart
@@ -317,7 +317,7 @@
// TODO: Handle invalidation of precompiled macros.
// TODO: Handle multiple macro libraries compiled to a single precompiled
// kernel file.
- var macroExecutor = state.options.macroExecutor;
+ var macroExecutor = state.processedOpts.macroExecutor;
var format = parsedArgs['precompiled-macro-format'];
for (var parts in (parsedArgs['precompiled-macro'] as List<String>)
.map((arg) => arg.split(';'))) {
diff --git a/pkg/js/lib/js.dart b/pkg/js/lib/js.dart
index 5f41532..8c867ae 100644
--- a/pkg/js/lib/js.dart
+++ b/pkg/js/lib/js.dart
@@ -5,6 +5,8 @@
/// Annotations to mark interfaces to JavaScript.
library js;
+import 'package:meta/meta.dart';
+
export 'dart:js' show allowInterop, allowInteropCaptureThis;
/// An annotation that indicates a library, class, or member is implemented
@@ -45,3 +47,16 @@
/// These classes should not contain any instance members, inherited or
/// otherwise, and should instead use static extension members.
const _StaticInterop staticInterop = _StaticInterop();
+
+/// NOTE: [trustTypes] is an experimental annotation that may disappear at any
+/// point in time. It exists solely to help users who wish to migrate classes
+/// from the older style of JS interop to the new static interop model but wish
+/// to preserve the older semantics for type checks. This annotation must be
+/// used alongside [staticInterop] and it affects any external methods in any
+/// extension to the static interop class.
+@experimental
+class _TrustTypes {
+ const _TrustTypes();
+}
+
+const _TrustTypes trustTypes = _TrustTypes();
diff --git a/pkg/js/pubspec.yaml b/pkg/js/pubspec.yaml
index 5f5000f..c8d12d3 100644
--- a/pkg/js/pubspec.yaml
+++ b/pkg/js/pubspec.yaml
@@ -6,5 +6,8 @@
environment:
sdk: ">=2.16.0-100.0.dev <3.0.0"
+dependencies:
+ meta: ^1.7.0
+
dev_dependencies:
lints: any
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 6ef2967..f3f7728 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -3855,6 +3855,7 @@
visitList(positionalParameters, v);
visitList(namedParameters, v);
returnType.accept(v);
+ futureValueType?.accept(v);
body?.accept(v);
}
@@ -3864,6 +3865,9 @@
v.transformList(positionalParameters, this);
v.transformList(namedParameters, this);
returnType = v.visitDartType(returnType);
+ if (futureValueType != null) {
+ futureValueType = v.visitDartType(futureValueType!);
+ }
if (body != null) {
body = v.transform(body!);
body?.parent = this;
@@ -3876,6 +3880,9 @@
v.transformVariableDeclarationList(positionalParameters, this);
v.transformVariableDeclarationList(namedParameters, this);
returnType = v.visitDartType(returnType, cannotRemoveSentinel);
+ if (futureValueType != null) {
+ futureValueType = v.visitDartType(futureValueType!, cannotRemoveSentinel);
+ }
if (body != null) {
body = v.transformOrRemoveStatement(body!);
body?.parent = this;
diff --git a/pkg/nnbd_migration/pubspec.yaml b/pkg/nnbd_migration/pubspec.yaml
index 19a70c2..4ed12f1 100644
--- a/pkg/nnbd_migration/pubspec.yaml
+++ b/pkg/nnbd_migration/pubspec.yaml
@@ -25,7 +25,7 @@
analyzer_utilities:
path: ../analyzer_utilities
http: ^0.13.4
- pedantic: ^1.9.0
+ lints: any
test: ^1.6.4
test_reflective_loader: ^0.2.0
diff --git a/pkg/test_runner/lib/src/output_log.dart b/pkg/test_runner/lib/src/output_log.dart
index fa8caae..7f04b1d 100644
--- a/pkg/test_runner/lib/src/output_log.dart
+++ b/pkg/test_runner/lib/src/output_log.dart
@@ -6,9 +6,9 @@
import 'dart:convert';
import 'dart:io';
-const _nonUtf8Error = '[test.dart: This test output contains non-UTF8 data]';
+const _nonUtf8Error = '[test.dart: This test output contains non-UTF8 data.]';
const _truncatedError =
- '[test.dart: This test output was too long and was truncated here.';
+ '[test.dart: This test output was too long and was truncated here.]';
/// Records the output from a test.
class OutputLog implements StreamConsumer<List<int>> {
@@ -37,6 +37,10 @@
if (_data.length + data.length > _maxLength) {
_data.addAll(data.take(_maxLength - _data.length));
+ final newline = utf8.encode("\n");
+ if (_data.last != newline.last) {
+ _data.addAll(newline);
+ }
_data.addAll(utf8.encode(_truncatedError));
_wasTruncated = true;
} else {
@@ -56,6 +60,10 @@
var malformed = utf8.decode(_data, allowMalformed: true);
_data.clear();
_data.addAll(utf8.encode(malformed));
+ final newline = utf8.encode("\n");
+ if (_data.last != newline.last) {
+ _data.addAll(newline);
+ }
_data.addAll(utf8.encode(_nonUtf8Error));
return true;
}
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 0f8cabf..d71457b 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -339,10 +339,10 @@
#endif // !defined(ARCH_IS_64_BIT) && !defined(FFI_UNIT_TESTS)
#elif defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) || \
defined(TARGET_ARCH_RISCV32)
-#if defined(HOST_ARCH_X64) && defined(TARGET_ARCH_ARM)
-// This is simarm_x64, which is the only case where host/target architecture
-// mismatch is allowed. Unless, we're running FFI unit tests.
-#define IS_SIMARM_X64 1
+#if defined(ARCH_IS_64_BIT) && defined(TARGET_ARCH_ARM)
+// This is simarm_x64 or simarm_arm64, which is the only case where host/target
+// architecture mismatch is allowed. Unless, we're running FFI unit tests.
+#define IS_SIMARM_HOST64 1
#elif !defined(ARCH_IS_32_BIT) && !defined(FFI_UNIT_TESTS)
#error Mismatched Host/Target architectures.
#endif // !defined(ARCH_IS_32_BIT) && !defined(FFI_UNIT_TESTS)
@@ -360,7 +360,7 @@
#elif defined(TARGET_ARCH_ARM)
#if !defined(HOST_ARCH_ARM)
#define TARGET_HOST_MISMATCH 1
-#if !defined(IS_SIMARM_X64)
+#if !defined(IS_SIMARM_HOST64)
#define USING_SIMULATOR 1
#endif
#endif
diff --git a/runtime/vm/app_snapshot.cc b/runtime/vm/app_snapshot.cc
index e2b8a40..ccdda66 100644
--- a/runtime/vm/app_snapshot.cc
+++ b/runtime/vm/app_snapshot.cc
@@ -8199,7 +8199,6 @@
TIMELINE_DURATION(thread(), Isolate, "ReadAlloc");
for (intptr_t i = 0; i < num_clusters_; i++) {
clusters_[i] = ReadCluster();
- TIMELINE_DURATION(thread(), Isolate, clusters_[i]->name());
clusters_[i]->ReadAlloc(this);
#if defined(DEBUG)
intptr_t serializers_next_ref_index_ = Read<int32_t>();
@@ -8215,7 +8214,6 @@
TIMELINE_DURATION(thread(), Isolate, "ReadFill");
SafepointWriteRwLocker ml(thread(), isolate_group()->program_lock());
for (intptr_t i = 0; i < num_clusters_; i++) {
- TIMELINE_DURATION(thread(), Isolate, clusters_[i]->name());
clusters_[i]->ReadFill(this, primary);
#if defined(DEBUG)
int32_t section_marker = Read<int32_t>();
@@ -8247,7 +8245,6 @@
{
TIMELINE_DURATION(thread(), Isolate, "PostLoad");
for (intptr_t i = 0; i < num_clusters_; i++) {
- TIMELINE_DURATION(thread(), Isolate, clusters_[i]->name());
clusters_[i]->PostLoad(this, refs, primary);
}
}
diff --git a/runtime/vm/compiler/assembler/disassembler_arm.cc b/runtime/vm/compiler/assembler/disassembler_arm.cc
index 51bb568..4d860a5 100644
--- a/runtime/vm/compiler/assembler/disassembler_arm.cc
+++ b/runtime/vm/compiler/assembler/disassembler_arm.cc
@@ -1512,14 +1512,14 @@
*object = NULL;
// TODO(36839): Make DecodeLoadObjectFromPoolOrThread work on simarm_x64.
-#if !defined(IS_SIMARM_X64)
+#if !defined(IS_SIMARM_HOST64)
if (!code.IsNull()) {
*object = &Object::Handle();
if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) {
*object = NULL;
}
}
-#endif // !defined(IS_SIMARM_X64)
+#endif // !defined(IS_SIMARM_HOST64)
}
#endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 367faf6..930ba5d 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -6534,14 +6534,13 @@
const Register saved_fp,
const Register temp0,
const Register temp1) {
- if (compiler::Assembler::EmittingComments()) {
- __ Comment("EmitParamMoves");
- }
+ __ Comment("EmitParamMoves");
// Moves for return pointer.
const auto& return_location =
marshaller_.Location(compiler::ffi::kResultIndex);
if (return_location.IsPointerToMemory()) {
+ __ Comment("return_location.IsPointerToMemory");
const auto& pointer_location =
return_location.AsPointerToMemory().pointer_location();
const auto& pointer_register =
@@ -6568,10 +6567,13 @@
arg_index++) {
const intptr_t num_defs = marshaller_.NumDefinitions(arg_index);
const auto& arg_target = marshaller_.Location(arg_index);
+ __ Comment("arg_index %" Pd " arg_target %s", arg_index,
+ arg_target.ToCString());
// First deal with moving all individual definitions passed in to the
// FfiCall to the right native location based on calling convention.
for (intptr_t i = 0; i < num_defs; i++) {
+ __ Comment(" def_index %" Pd, def_index);
const Location origin = rebase.Rebase(locs()->in(def_index));
const Representation origin_rep =
RequiredInputRepresentation(def_index) == kTagged
@@ -6594,6 +6596,23 @@
// originate from parameters and thus are non-constant.
UNREACHABLE();
} else {
+#if defined(INCLUDE_IL_PRINTER)
+ __ Comment("def_target %s <- origin %s %s", def_target.ToCString(),
+ origin.ToCString(), RepresentationToCString(origin_rep));
+#endif // defined(INCLUDE_IL_PRINTER)
+#ifdef DEBUG
+ // Stack arguments split are in word-size chunks. These chunks can copy
+ // too much. However, that doesn't matter in practise because we process
+ // the stack in order.
+ // It only matters for the last chunk, it should not overwrite what was
+ // already on the stack.
+ if (def_target.IsStack()) {
+ const auto& def_target_stack = def_target.AsStack();
+ ASSERT(def_target_stack.offset_in_bytes() +
+ def_target.payload_type().SizeInBytes() <=
+ marshaller_.RequiredStackSpaceInBytes());
+ }
+#endif
compiler->EmitMoveToNative(def_target, origin, origin_rep, &temp_alloc);
}
def_index++;
@@ -6604,6 +6623,7 @@
// Note that the step above has already moved the pointer into the expected
// native location.
if (arg_target.IsPointerToMemory()) {
+ __ Comment("arg_target.IsPointerToMemory");
NoTemporaryAllocator temp_alloc;
const auto& pointer_loc =
arg_target.AsPointerToMemory().pointer_location();
@@ -6635,13 +6655,13 @@
const auto& src = compiler::ffi::NativeRegistersLocation(
zone_, pointer_loc.payload_type(), pointer_loc.container_type(),
temp0);
+ __ Comment("pointer_loc %s <- src %s", pointer_loc.ToCString(),
+ src.ToCString());
compiler->EmitNativeMove(pointer_loc, src, &temp_alloc);
}
}
- if (compiler::Assembler::EmittingComments()) {
- __ Comment("EmitParamMovesEnd");
- }
+ __ Comment("EmitParamMovesEnd");
}
void FfiCallInstr::EmitReturnMoves(FlowGraphCompiler* compiler,
diff --git a/runtime/vm/compiler/ffi/marshaller.cc b/runtime/vm/compiler/ffi/marshaller.cc
index ca4f6d6..91497a7 100644
--- a/runtime/vm/compiler/ffi/marshaller.cc
+++ b/runtime/vm/compiler/ffi/marshaller.cc
@@ -453,6 +453,13 @@
// First the native arguments are on the stack.
// This is governed by the native ABI, the rest we can chose freely.
stack_offset += native_calling_convention_.StackTopInBytes();
+#if (defined(DART_TARGET_OS_MACOS_IOS) || defined(DART_TARGET_OS_MACOS)) && \
+ defined(TARGET_ARCH_ARM64)
+ // Add extra padding for possibly non stack-aligned word-size writes.
+ // TODO(https://dartbug.com/48806): Re-engineer the moves to not over-
+ // approximate struct sizes on stack.
+ stack_offset += 4;
+#endif
stack_offset = Utils::RoundUp(stack_offset, compiler::target::kWordSize);
if (arg_index == kResultIndex) {
return stack_offset;
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index bf4c995..2ccf215 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -155,7 +155,7 @@
static DartInitializationState init_state_;
static void CheckOffsets() {
-#if !defined(IS_SIMARM_X64)
+#if !defined(IS_SIMARM_HOST64)
// These offsets are embedded in precompiled instructions. We need the
// compiler and the runtime to agree.
bool ok = true;
@@ -241,7 +241,7 @@
#undef CHECK_CONSTANT
#undef CHECK_OFFSET
#undef CHECK_PAYLOAD_SIZEOF
-#endif // !defined(IS_SIMARM_X64)
+#endif // !defined(IS_SIMARM_HOST64)
}
char* Dart::DartInit(const Dart_InitializeParams* params) {
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 2081ad0..0b79720 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -169,7 +169,7 @@
Thread* thread) {
ASSERT(!code.IsNull());
ASSERT(thread->no_callback_scope_depth() == 0);
- ASSERT(!IsolateGroup::Current()->null_safety_not_set());
+ ASSERT(!thread->isolate_group()->null_safety_not_set());
const uword stub = StubCode::InvokeDartCode().EntryPoint();
SuspendLongJumpScope suspend_long_jump_scope(thread);
diff --git a/runtime/vm/globals.h b/runtime/vm/globals.h
index c564a48..559dc44 100644
--- a/runtime/vm/globals.h
+++ b/runtime/vm/globals.h
@@ -112,7 +112,7 @@
#define SUPPORT_TIMELINE 1
#endif
-#if defined(ARCH_IS_64_BIT) && !defined(IS_SIMARM_X64)
+#if defined(ARCH_IS_64_BIT) && !defined(IS_SIMARM_HOST64)
#define HASH_IN_OBJECT_HEADER 1
#endif
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 713bf97..68ba680 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -67,10 +67,9 @@
}
}
-uword Heap::AllocateNew(intptr_t size) {
- ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0);
- CollectForDebugging();
- Thread* thread = Thread::Current();
+uword Heap::AllocateNew(Thread* thread, intptr_t size) {
+ ASSERT(thread->no_safepoint_scope_depth() == 0);
+ CollectForDebugging(thread);
uword addr = new_space_.TryAllocate(thread, size);
if (LIKELY(addr != 0)) {
return addr;
@@ -89,18 +88,17 @@
// It is possible a GC doesn't clear enough space.
// In that case, we must fall through and allocate into old space.
- return AllocateOld(size, OldPage::kData);
+ return AllocateOld(thread, size, OldPage::kData);
}
-uword Heap::AllocateOld(intptr_t size, OldPage::PageType type) {
- ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0);
+uword Heap::AllocateOld(Thread* thread, intptr_t size, OldPage::PageType type) {
+ ASSERT(thread->no_safepoint_scope_depth() == 0);
if (old_space_.GrowthControlState()) {
- CollectForDebugging();
+ CollectForDebugging(thread);
uword addr = old_space_.TryAllocate(size, type);
if (addr != 0) {
return addr;
}
- Thread* thread = Thread::Current();
// Wait for any GC tasks that are in progress.
WaitForSweeperTasks(thread);
addr = old_space_.TryAllocate(size, type);
@@ -135,7 +133,7 @@
}
if (old_space_.GrowthControlState()) {
- WaitForSweeperTasks(Thread::Current());
+ WaitForSweeperTasks(thread);
old_space_.TryReleaseReservation();
} else {
// We may or may not be a safepoint, so we don't know how to wait for the
@@ -428,7 +426,7 @@
void Heap::CollectNewSpaceGarbage(Thread* thread,
GCType type,
GCReason reason) {
- NoActiveIsolateScope no_active_isolate_scope;
+ NoActiveIsolateScope no_active_isolate_scope(thread);
ASSERT(reason != GCReason::kPromotion);
ASSERT(reason != GCReason::kFinalize);
if (thread->isolate_group() == Dart::vm_isolate_group()) {
@@ -468,7 +466,7 @@
void Heap::CollectOldSpaceGarbage(Thread* thread,
GCType type,
GCReason reason) {
- NoActiveIsolateScope no_active_isolate_scope;
+ NoActiveIsolateScope no_active_isolate_scope(thread);
ASSERT(type != GCType::kScavenge);
ASSERT(reason != GCReason::kNewSpace);
@@ -704,9 +702,9 @@
gc_on_nth_allocation_ = num_allocations;
}
-void Heap::CollectForDebugging() {
+void Heap::CollectForDebugging(Thread* thread) {
if (gc_on_nth_allocation_ == kNoForcedGarbageCollection) return;
- if (Thread::Current()->IsAtSafepoint()) {
+ if (thread->IsAtSafepoint()) {
// CollectAllGarbage is not supported when we are at a safepoint.
// Allocating when at a safepoint is not a common case.
return;
@@ -717,7 +715,7 @@
gc_on_nth_allocation_ = kNoForcedGarbageCollection;
} else {
// Prevent generated code from using the TLAB fast path on next allocation.
- new_space_.AbandonRemainingTLABForDebugging(Thread::Current());
+ new_space_.AbandonRemainingTLABForDebugging(thread);
}
}
diff --git a/runtime/vm/heap/heap.h b/runtime/vm/heap/heap.h
index 705e5a9..8248ee1 100644
--- a/runtime/vm/heap/heap.h
+++ b/runtime/vm/heap/heap.h
@@ -59,19 +59,19 @@
Scavenger* new_space() { return &new_space_; }
PageSpace* old_space() { return &old_space_; }
- uword Allocate(intptr_t size, Space space) {
+ uword Allocate(Thread* thread, intptr_t size, Space space) {
ASSERT(!read_only_);
switch (space) {
case kNew:
// Do not attempt to allocate very large objects in new space.
if (!IsAllocatableInNewSpace(size)) {
- return AllocateOld(size, OldPage::kData);
+ return AllocateOld(thread, size, OldPage::kData);
}
- return AllocateNew(size);
+ return AllocateNew(thread, size);
case kOld:
- return AllocateOld(size, OldPage::kData);
+ return AllocateOld(thread, size, OldPage::kData);
case kCode:
- return AllocateOld(size, OldPage::kExecutable);
+ return AllocateOld(thread, size, OldPage::kExecutable);
default:
UNREACHABLE();
}
@@ -325,8 +325,8 @@
intptr_t max_new_gen_semi_words, // Max capacity of new semi-space.
intptr_t max_old_gen_words);
- uword AllocateNew(intptr_t size);
- uword AllocateOld(intptr_t size, OldPage::PageType type);
+ uword AllocateNew(Thread* thread, intptr_t size);
+ uword AllocateOld(Thread* thread, intptr_t size, OldPage::PageType type);
// Visit all pointers. Caller must ensure concurrent sweeper is not running,
// and the visitor must not allocate.
@@ -355,7 +355,7 @@
void AddRegionsToObjectSet(ObjectSet* set) const;
// Trigger major GC if 'gc_on_nth_allocation_' is set.
- void CollectForDebugging();
+ void CollectForDebugging(Thread* thread);
IsolateGroup* isolate_group_;
bool is_vm_isolate_;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index a8eb8b1..fc87889 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -538,6 +538,7 @@
void Object::InitNullAndBool(IsolateGroup* isolate_group) {
// Should only be run by the vm isolate.
ASSERT(isolate_group == Dart::vm_isolate_group());
+ Thread* thread = Thread::Current();
auto heap = isolate_group->heap();
// TODO(iposva): NoSafepointScope needs to be added here.
@@ -547,7 +548,8 @@
// 'null_' must be the first object allocated as it is used in allocation to
// clear the object.
{
- uword address = heap->Allocate(Instance::InstanceSize(), Heap::kOld);
+ uword address =
+ heap->Allocate(thread, Instance::InstanceSize(), Heap::kOld);
null_ = static_cast<InstancePtr>(address + kHeapObjectTag);
// The call below is using 'null_' to initialize itself.
InitializeObject(address, kNullCid, Instance::InstanceSize(),
@@ -561,14 +563,14 @@
// otherwise identical.
{
// Allocate a dummy bool object to give true the desired alignment.
- uword address = heap->Allocate(Bool::InstanceSize(), Heap::kOld);
+ uword address = heap->Allocate(thread, Bool::InstanceSize(), Heap::kOld);
InitializeObject(address, kBoolCid, Bool::InstanceSize(),
Bool::ContainsCompressedPointers());
static_cast<BoolPtr>(address + kHeapObjectTag)->untag()->value_ = false;
}
{
// Allocate true.
- uword address = heap->Allocate(Bool::InstanceSize(), Heap::kOld);
+ uword address = heap->Allocate(thread, Bool::InstanceSize(), Heap::kOld);
true_ = static_cast<BoolPtr>(address + kHeapObjectTag);
InitializeObject(address, kBoolCid, Bool::InstanceSize(),
Bool::ContainsCompressedPointers());
@@ -577,7 +579,7 @@
}
{
// Allocate false.
- uword address = heap->Allocate(Bool::InstanceSize(), Heap::kOld);
+ uword address = heap->Allocate(thread, Bool::InstanceSize(), Heap::kOld);
false_ = static_cast<BoolPtr>(address + kHeapObjectTag);
InitializeObject(address, kBoolCid, Bool::InstanceSize(),
Bool::ContainsCompressedPointers());
@@ -744,7 +746,7 @@
// Allocate and initialize the class class.
{
intptr_t size = Class::InstanceSize();
- uword address = heap->Allocate(size, Heap::kOld);
+ uword address = heap->Allocate(thread, size, Heap::kOld);
class_class_ = static_cast<ClassPtr>(address + kHeapObjectTag);
InitializeObject(address, Class::kClassId, size,
Class::ContainsCompressedPointers());
@@ -979,7 +981,7 @@
// Allocate and initialize the empty_array instance.
{
- uword address = heap->Allocate(Array::InstanceSize(0), Heap::kOld);
+ uword address = heap->Allocate(thread, Array::InstanceSize(0), Heap::kOld);
InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(0),
Array::ContainsCompressedPointers());
Array::initializeHandle(empty_array_,
@@ -991,7 +993,7 @@
Smi& smi = Smi::Handle();
// Allocate and initialize the zero_array instance.
{
- uword address = heap->Allocate(Array::InstanceSize(1), Heap::kOld);
+ uword address = heap->Allocate(thread, Array::InstanceSize(1), Heap::kOld);
InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(1),
Array::ContainsCompressedPointers());
Array::initializeHandle(zero_array_,
@@ -1004,7 +1006,8 @@
// Allocate and initialize the canonical empty context scope object.
{
- uword address = heap->Allocate(ContextScope::InstanceSize(0), Heap::kOld);
+ uword address =
+ heap->Allocate(thread, ContextScope::InstanceSize(0), Heap::kOld);
InitializeObject(address, kContextScopeCid, ContextScope::InstanceSize(0),
ContextScope::ContainsCompressedPointers());
ContextScope::initializeHandle(
@@ -1019,7 +1022,8 @@
// Allocate and initialize the canonical empty object pool object.
{
- uword address = heap->Allocate(ObjectPool::InstanceSize(0), Heap::kOld);
+ uword address =
+ heap->Allocate(thread, ObjectPool::InstanceSize(0), Heap::kOld);
InitializeObject(address, kObjectPoolCid, ObjectPool::InstanceSize(0),
ObjectPool::ContainsCompressedPointers());
ObjectPool::initializeHandle(
@@ -1033,7 +1037,7 @@
// Allocate and initialize the empty_compressed_stackmaps instance.
{
const intptr_t instance_size = CompressedStackMaps::InstanceSize(0);
- uword address = heap->Allocate(instance_size, Heap::kOld);
+ uword address = heap->Allocate(thread, instance_size, Heap::kOld);
InitializeObject(address, kCompressedStackMapsCid, instance_size,
CompressedStackMaps::ContainsCompressedPointers());
CompressedStackMaps::initializeHandle(
@@ -1045,7 +1049,8 @@
// Allocate and initialize the empty_descriptors instance.
{
- uword address = heap->Allocate(PcDescriptors::InstanceSize(0), Heap::kOld);
+ uword address =
+ heap->Allocate(thread, PcDescriptors::InstanceSize(0), Heap::kOld);
InitializeObject(address, kPcDescriptorsCid, PcDescriptors::InstanceSize(0),
PcDescriptors::ContainsCompressedPointers());
PcDescriptors::initializeHandle(
@@ -1058,8 +1063,8 @@
// Allocate and initialize the canonical empty variable descriptor object.
{
- uword address =
- heap->Allocate(LocalVarDescriptors::InstanceSize(0), Heap::kOld);
+ uword address = heap->Allocate(thread, LocalVarDescriptors::InstanceSize(0),
+ Heap::kOld);
InitializeObject(address, kLocalVarDescriptorsCid,
LocalVarDescriptors::InstanceSize(0),
LocalVarDescriptors::ContainsCompressedPointers());
@@ -1076,7 +1081,7 @@
// and can share this canonical descriptor.
{
uword address =
- heap->Allocate(ExceptionHandlers::InstanceSize(0), Heap::kOld);
+ heap->Allocate(thread, ExceptionHandlers::InstanceSize(0), Heap::kOld);
InitializeObject(address, kExceptionHandlersCid,
ExceptionHandlers::InstanceSize(0),
ExceptionHandlers::ContainsCompressedPointers());
@@ -1090,7 +1095,8 @@
// Allocate and initialize the canonical empty type arguments object.
{
- uword address = heap->Allocate(TypeArguments::InstanceSize(0), Heap::kOld);
+ uword address =
+ heap->Allocate(thread, TypeArguments::InstanceSize(0), Heap::kOld);
InitializeObject(address, kTypeArgumentsCid, TypeArguments::InstanceSize(0),
TypeArguments::ContainsCompressedPointers());
TypeArguments::initializeHandle(
@@ -2666,7 +2672,7 @@
ASSERT(thread->no_callback_scope_depth() == 0);
Heap* heap = thread->heap();
- uword address = heap->Allocate(size, space);
+ uword address = heap->Allocate(thread, size, space);
if (UNLIKELY(address == 0)) {
// SuspendLongJumpScope during Dart entry ensures that if a longjmp base is
// available, it is the innermost error handler, so check for a longjmp base
@@ -2684,7 +2690,7 @@
OUT_OF_MEMORY();
}
}
- NoSafepointScope no_safepoint;
+ NoSafepointScope no_safepoint(thread);
ObjectPtr raw_obj;
InitializeObject(address, cls_id, size, compressed);
raw_obj = static_cast<ObjectPtr>(address + kHeapObjectTag);
@@ -19714,6 +19720,11 @@
if (cls.EnsureIsAllocateFinalized(thread) != Error::null()) {
return Instance::null();
}
+ return NewAlreadyFinalized(cls, space);
+}
+
+InstancePtr Instance::NewAlreadyFinalized(const Class& cls, Heap::Space space) {
+ ASSERT(cls.is_allocate_finalized());
intptr_t instance_size = cls.host_instance_size();
ASSERT(instance_size > 0);
ObjectPtr raw = Object::Allocate(cls.id(), instance_size, space,
@@ -24306,7 +24317,8 @@
ArrayPtr Array::Grow(const Array& source,
intptr_t new_length,
Heap::Space space) {
- Zone* zone = Thread::Current()->zone();
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
const Array& result = Array::Handle(zone, Array::New(new_length, space));
intptr_t len = 0;
if (!source.IsNull()) {
@@ -24319,7 +24331,7 @@
PassiveObject& obj = PassiveObject::Handle(zone);
for (int i = 0; i < len; i++) {
obj = source.At(i);
- result.SetAt(i, obj);
+ result.SetAt(i, obj, thread);
}
return result.ptr();
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 4d16d9c..7d9ffe0 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -7714,6 +7714,8 @@
}
static InstancePtr New(const Class& cls, Heap::Space space = Heap::kNew);
+ static InstancePtr NewAlreadyFinalized(const Class& cls,
+ Heap::Space space = Heap::kNew);
// Array/list element address computations.
static intptr_t DataOffsetFor(intptr_t cid);
@@ -10342,9 +10344,12 @@
}
template <std::memory_order order = std::memory_order_relaxed>
void SetAt(intptr_t index, const Object& value) const {
- // TODO(iposva): Add storing NoSafepointScope.
untag()->set_element<order>(index, value.ptr());
}
+ template <std::memory_order order = std::memory_order_relaxed>
+ void SetAt(intptr_t index, const Object& value, Thread* thread) const {
+ untag()->set_element<order>(index, value.ptr(), thread);
+ }
// Access to the array with acquire release semantics.
ObjectPtr AtAcquire(intptr_t index) const {
@@ -10479,9 +10484,11 @@
memmove(const_cast<CompressedObjectPtr*>(to), from,
count * kBytesPerElement);
} else {
+ Thread* thread = Thread::Current();
const uword heap_base = ptr()->heap_base();
for (intptr_t i = 0; i < count; ++i) {
- StoreArrayPointer(&to[i], from[i].Decompress(heap_base));
+ untag()->StoreArrayPointer(&to[i], from[i].Decompress(heap_base),
+ thread);
}
}
}
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 89dae69..dc4fcf3 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -601,9 +601,7 @@
}
}
- template <typename type,
- typename compressed_type,
- std::memory_order order = std::memory_order_relaxed>
+ template <typename type, typename compressed_type, std::memory_order order>
void StoreCompressedArrayPointer(compressed_type const* addr, type value) {
reinterpret_cast<std::atomic<compressed_type>*>(
const_cast<compressed_type*>(addr))
@@ -613,6 +611,18 @@
}
}
+ template <typename type, typename compressed_type, std::memory_order order>
+ void StoreCompressedArrayPointer(compressed_type const* addr,
+ type value,
+ Thread* thread) {
+ reinterpret_cast<std::atomic<compressed_type>*>(
+ const_cast<compressed_type*>(addr))
+ ->store(static_cast<compressed_type>(value), order);
+ if (value->IsHeapObject()) {
+ CheckArrayPointerStore(addr, value, thread);
+ }
+ }
+
template <typename type, typename compressed_type>
void StoreCompressedArrayPointer(compressed_type const* addr,
type value,
@@ -863,6 +873,10 @@
void set_##accessor_name(intptr_t index, type value) { \
StoreArrayPointer<type, order>(&array_name()[index], value); \
} \
+ template <std::memory_order order = std::memory_order_relaxed> \
+ void set_##accessor_name(intptr_t index, type value, Thread* thread) { \
+ StoreArrayPointer<type, order>(&array_name()[index], value, thread); \
+ } \
\
protected: \
type* array_name() { OPEN_ARRAY_START(type, type); } \
@@ -881,6 +895,11 @@
StoreCompressedArrayPointer<type, Compressed##type, order>( \
&array_name()[index], value); \
} \
+ template <std::memory_order order = std::memory_order_relaxed> \
+ void set_##accessor_name(intptr_t index, type value, Thread* thread) { \
+ StoreCompressedArrayPointer<type, Compressed##type, order>( \
+ &array_name()[index], value, thread); \
+ } \
\
protected: \
Compressed##type* array_name() { \
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index a249423..99601df 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -460,11 +460,9 @@
// Return value: newly allocated object.
DEFINE_RUNTIME_ENTRY(AllocateObject, 2) {
const Class& cls = Class::CheckedHandle(zone, arguments.ArgAt(0));
- const Error& error =
- Error::Handle(zone, cls.EnsureIsAllocateFinalized(thread));
- ThrowIfError(error);
- const Instance& instance =
- Instance::Handle(zone, Instance::New(cls, SpaceForRuntimeAllocation()));
+ ASSERT(cls.is_allocate_finalized());
+ const Instance& instance = Instance::Handle(
+ zone, Instance::NewAlreadyFinalized(cls, SpaceForRuntimeAllocation()));
arguments.SetReturn(instance);
if (cls.NumTypeArguments() == 0) {
@@ -1393,7 +1391,7 @@
#if !defined(PRODUCT)
// Monomorphic/megamorphic do not check the isolate's stepping flag.
- if (Isolate::Current()->has_attempted_stepping()) return;
+ if (thread->isolate()->has_attempted_stepping()) return;
#endif
// Monomorphic/megamorphic calls are only for unoptimized code.
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 9f3a5bf..e8ad780 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -437,7 +437,10 @@
if ((interrupt_bits & kVMInterrupt) != 0) {
CheckForSafepoint();
if (isolate_group()->store_buffer()->Overflowed()) {
- heap()->CollectGarbage(this, GCType::kScavenge, GCReason::kStoreBuffer);
+ // Evacuate: If the popular store buffer targets are copied instead of
+ // promoted, the store buffer won't shrink and a second scavenge will
+ // occur that does promote them.
+ heap()->CollectGarbage(this, GCType::kEvacuate, GCReason::kStoreBuffer);
}
#if !defined(PRODUCT)
diff --git a/sdk/lib/_internal/js_runtime/lib/late_helper.dart b/sdk/lib/_internal/js_runtime/lib/late_helper.dart
index 1643555..ceabcd7 100644
--- a/sdk/lib/_internal/js_runtime/lib/late_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/late_helper.dart
@@ -6,20 +6,8 @@
import 'dart:_internal' show LateError, createSentinel, isSentinel;
-@pragma('dart2js:tryInline')
-void throwLateFieldNI(String fieldName) => throw LateError.fieldNI(fieldName);
-@pragma('dart2js:tryInline')
-void throwLateFieldAI(String fieldName) => throw LateError.fieldAI(fieldName);
-@pragma('dart2js:tryInline')
void throwLateFieldADI(String fieldName) => throw LateError.fieldADI(fieldName);
-@pragma('dart2js:tryInline')
-void throwUnnamedLateFieldNI() => throw LateError.fieldNI('');
-@pragma('dart2js:tryInline')
-void throwUnnamedLateFieldAI() => throw LateError.fieldAI('');
-@pragma('dart2js:tryInline')
-void throwUnnamedLateFieldADI() => throw LateError.fieldADI('');
-
/// A boxed variable used for lowering uninitialized `late` variables when they
/// are locals or statics.
class _Cell {
@@ -125,8 +113,19 @@
// Helpers for lowering late instance fields:
// TODO(fishythefish): Support specialization of sentinels based on type.
-external T _lateReadCheck<T>(Object? value, String name);
+@pragma('dart2js:noInline')
+@pragma('dart2js:as:trust')
+T _lateReadCheck<T>(Object? value, String name) {
+ if (isSentinel(value)) throw LateError.fieldNI(name);
+ return value as T;
+}
-external void _lateWriteOnceCheck(Object? value, String name);
+@pragma('dart2js:noInline')
+void _lateWriteOnceCheck(Object? value, String name) {
+ if (!isSentinel(value)) throw LateError.fieldAI(name);
+}
-external void _lateInitializeOnceCheck(Object? value, String name);
+@pragma('dart2js:noInline')
+void _lateInitializeOnceCheck(Object? value, String name) {
+ if (!isSentinel(value)) throw LateError.fieldADI(name);
+}
diff --git a/sdk/lib/js_util/js_util.dart b/sdk/lib/js_util/js_util.dart
index 9af9ea6..d0db609 100644
--- a/sdk/lib/js_util/js_util.dart
+++ b/sdk/lib/js_util/js_util.dart
@@ -74,6 +74,10 @@
T getProperty<T>(Object o, Object name) =>
JS<dynamic>('Object|Null', '#[#]', o, name);
+/// Similar to [getProperty] but introduces an unsound implicit cast to `T`.
+T _getPropertyTrustType<T>(Object o, Object name) =>
+ JS<T>('Object|Null', '#[#]', o, name);
+
// A CFE transformation may optimize calls to `setProperty`, when [value] is
// statically known to be a non-function.
T setProperty<T>(Object o, Object name, T? value) {
@@ -95,18 +99,38 @@
return JS<dynamic>('Object|Null', '#[#].apply(#, #)', o, method, o, args);
}
+/// Similar to [callMethod] but introduces an unsound implicit cast to `T`.
+T _callMethodTrustType<T>(Object o, String method, List<Object?> args) {
+ assertInteropArgs(args);
+ return JS<T>('Object|Null', '#[#].apply(#, #)', o, method, o, args);
+}
+
/// Unchecked version for 0 arguments, only used in a CFE transformation.
@pragma('dart2js:tryInline')
T _callMethodUnchecked0<T>(Object o, String method) {
return JS<dynamic>('Object|Null', '#[#]()', o, method);
}
+/// Similar to [_callMethodUnchecked] but introduces an unsound implicit cast
+/// to `T`.
+@pragma('dart2js:tryInline')
+T _callMethodUncheckedTrustType0<T>(Object o, String method) {
+ return JS<T>('Object|Null', '#[#]()', o, method);
+}
+
/// Unchecked version for 1 argument, only used in a CFE transformation.
@pragma('dart2js:tryInline')
T _callMethodUnchecked1<T>(Object o, String method, Object? arg1) {
return JS<dynamic>('Object|Null', '#[#](#)', o, method, arg1);
}
+/// Similar to [_callMethodUnchecked1] but introduces an unsound implicit cast
+/// to `T`.
+@pragma('dart2js:tryInline')
+T _callMethodUncheckedTrustType1<T>(Object o, String method, Object? arg1) {
+ return JS<T>('Object|Null', '#[#](#)', o, method, arg1);
+}
+
/// Unchecked version for 2 arguments, only used in a CFE transformation.
@pragma('dart2js:tryInline')
T _callMethodUnchecked2<T>(
@@ -114,6 +138,14 @@
return JS<dynamic>('Object|Null', '#[#](#, #)', o, method, arg1, arg2);
}
+/// Similar to [_callMethodUnchecked2] but introduces an unsound implicit cast
+/// to `T`.
+@pragma('dart2js:tryInline')
+T _callMethodUncheckedTrustType2<T>(
+ Object o, String method, Object? arg1, Object? arg2) {
+ return JS<T>('Object|Null', '#[#](#, #)', o, method, arg1, arg2);
+}
+
/// Unchecked version for 3 arguments, only used in a CFE transformation.
@pragma('dart2js:tryInline')
T _callMethodUnchecked3<T>(
@@ -122,6 +154,14 @@
'Object|Null', '#[#](#, #, #)', o, method, arg1, arg2, arg3);
}
+/// Similar to [_callMethodUnchecked3] but introduces an unsound implicit cast
+/// to `T`.
+@pragma('dart2js:tryInline')
+T _callMethodUncheckedTrustType3<T>(
+ Object o, String method, Object? arg1, Object? arg2, Object? arg3) {
+ return JS<T>('Object|Null', '#[#](#, #, #)', o, method, arg1, arg2, arg3);
+}
+
/// Unchecked version for 4 arguments, only used in a CFE transformation.
@pragma('dart2js:tryInline')
T _callMethodUnchecked4<T>(Object o, String method, Object? arg1, Object? arg2,
@@ -130,6 +170,15 @@
'Object|Null', '#[#](#, #, #, #)', o, method, arg1, arg2, arg3, arg4);
}
+/// Similar to [_callMethodUnchecked4] but introduces an unsound implicit cast
+/// to `T`.
+@pragma('dart2js:tryInline')
+T _callMethodUncheckedTrustType4<T>(Object o, String method, Object? arg1,
+ Object? arg2, Object? arg3, Object? arg4) {
+ return JS<T>(
+ 'Object|Null', '#[#](#, #, #, #)', o, method, arg1, arg2, arg3, arg4);
+}
+
/// Check whether [o] is an instance of [type].
///
/// The value in [type] is expected to be a JS-interop object that
diff --git a/tests/lib/js/static_interop_test/futurevaluetype_test.dart b/tests/lib/js/static_interop_test/futurevaluetype_test.dart
new file mode 100644
index 0000000..ac2a5df
--- /dev/null
+++ b/tests/lib/js/static_interop_test/futurevaluetype_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2022, 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.
+
+// Test that `FunctionNode`'s `futureValueType`s are correctly transformed.
+// See https://github.com/dart-lang/sdk/issues/48835 for more details.
+
+@JS()
+library futurevaluetype_test;
+
+import 'dart:html';
+
+import 'package:js/js.dart';
+
+@JS()
+@staticInterop
+class JSWindow {}
+
+// `futureValueType` corresponds to the `JSWindow` type parameter in the return
+// value here. If this isn't correctly erased, we should see a runtime type
+// error when using this method, as we'll be attemting to return a `@Native`
+// type (`Window`) where a `package:js` type is expected instead of a
+// `JavaScriptObject`.
+Future<JSWindow> returnInteropType() async {
+ return window as JSWindow;
+}
+
+void main() async {
+ await returnInteropType();
+}
diff --git a/tests/lib/js/trust_types_annotation_test.dart b/tests/lib/js/trust_types_annotation_test.dart
new file mode 100644
index 0000000..7248ad5
--- /dev/null
+++ b/tests/lib/js/trust_types_annotation_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, 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.
+
+import 'package:js/js.dart';
+
+@JS()
+@trustTypes
+class Incorrect {}
+// ^
+// [web] JS interop class 'Incorrect' has an `@trustTypes` annotation, but no `@staticInterop` annotation.
diff --git a/tests/lib/js/trust_types_test.dart b/tests/lib/js/trust_types_test.dart
new file mode 100644
index 0000000..2cbfb37
--- /dev/null
+++ b/tests/lib/js/trust_types_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2022, 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.
+
+// Test that the [trustTypes] annotation has the same semantics as the older
+// style of js interop.
+
+import 'package:js/js.dart';
+import 'package:expect/expect.dart';
+
+class NonExistent {}
+
+@JS()
+@staticInterop
+@trustTypes
+class TrustMe {
+ external factory TrustMe();
+}
+
+extension TrustMeExtension on TrustMe {
+ external List<NonExistent> get foos;
+ external List<NonExistent> callFoos();
+ external List<NonExistent> callFoos1(int ignored);
+ external List<NonExistent> callFoos2(int ignored1, int ignored2);
+ external List<NonExistent> callFoos3(
+ int ignored1, int ignored2, int ignored3);
+ external List<NonExistent> callFoos4(
+ int ignored1, int ignored2, int ignored3, int ignored4);
+ external List<NonExistent> callFoos5(
+ int ignored1, int ignored2, int ignored3, int ignored4, int ignored5);
+ external String get fooPrimitive;
+}
+
+@JS()
+external void eval(String code);
+
+void main() {
+ eval(r'''
+ TrustMe = function TrustMe() {
+ this.foos = 'not a list 1';
+ this.fooPrimitive = 5;
+ this.callFoos = function() {
+ return 'not a list 2';
+ }
+ this.callFoos1 = function(a) {
+ return 'not a list 3';
+ }
+ this.callFoos2 = function(a, b) {
+ return 'not a list 4';
+ }
+ this.callFoos3 = function(a, b, c) {
+ return 'not a list 5';
+ }
+ this.callFoos4 = function(a, b, c, d) {
+ return 'not a list 6';
+ }
+ this.callFoos5 = function(a, b, c, d, e) {
+ return 'not a list 7';
+ }
+ }
+ ''');
+ final trusted = TrustMe();
+ Expect.equals('not a list 1', trusted.foos.toString());
+ Expect.equals('not a list 2', trusted.callFoos().toString());
+ Expect.equals('not a list 3', trusted.callFoos1(1).toString());
+ Expect.equals('not a list 4', trusted.callFoos2(1, 1).toString());
+ Expect.equals('not a list 5', trusted.callFoos3(1, 1, 1).toString());
+ Expect.equals('not a list 6', trusted.callFoos4(1, 1, 1, 1).toString());
+
+ final falseList = trusted.callFoos5(1, 1, 1, 1, 1);
+ Expect.equals('not a list 7', falseList.toString());
+ Expect.throws(() => falseList.removeAt(0));
+
+ final falseString = trusted.fooPrimitive;
+ Expect.equals(5, falseString);
+ Expect.throws(() => falseString.codeUnitAt(0));
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 0b262df..2f3fffb 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -12,7 +12,8 @@
isolate/issue_24243_parent_isolate_test: Skip # Requires checked mode
[ $runtime == d8 ]
-js/js_util/javascriptobject_extensions_test.dart: SkipByDesign # Uses dart:html.
+js/js_util/javascriptobject_extensions_test: SkipByDesign # Uses dart:html.
+js/static_interop_test/futurevaluetype_test: SkipByDesign # Uses dart:html.
[ $runtime == dart_precompiled ]
isolate/package_config_getter_test: SkipByDesign # AOT mode doesn't preserve package structure.
@@ -54,6 +55,7 @@
js/method_call_on_object_test: SkipByDesign # Issue 42085.
js/mock_test/*: SkipByDesign # Issue 42085.
js/parameters_test: SkipByDesign # Issue 42085.
+js/trust_types_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
[ $compiler != dart2js && $compiler != dartdevk ]
web/*: SkipByDesign
diff --git a/tests/lib_2/js/static_interop_test/futurevaluetype_test.dart b/tests/lib_2/js/static_interop_test/futurevaluetype_test.dart
new file mode 100644
index 0000000..ac2a5df
--- /dev/null
+++ b/tests/lib_2/js/static_interop_test/futurevaluetype_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2022, 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.
+
+// Test that `FunctionNode`'s `futureValueType`s are correctly transformed.
+// See https://github.com/dart-lang/sdk/issues/48835 for more details.
+
+@JS()
+library futurevaluetype_test;
+
+import 'dart:html';
+
+import 'package:js/js.dart';
+
+@JS()
+@staticInterop
+class JSWindow {}
+
+// `futureValueType` corresponds to the `JSWindow` type parameter in the return
+// value here. If this isn't correctly erased, we should see a runtime type
+// error when using this method, as we'll be attemting to return a `@Native`
+// type (`Window`) where a `package:js` type is expected instead of a
+// `JavaScriptObject`.
+Future<JSWindow> returnInteropType() async {
+ return window as JSWindow;
+}
+
+void main() async {
+ await returnInteropType();
+}
diff --git a/tests/lib_2/js/trust_types_annotation_test.dart b/tests/lib_2/js/trust_types_annotation_test.dart
new file mode 100644
index 0000000..7248ad5
--- /dev/null
+++ b/tests/lib_2/js/trust_types_annotation_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, 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.
+
+import 'package:js/js.dart';
+
+@JS()
+@trustTypes
+class Incorrect {}
+// ^
+// [web] JS interop class 'Incorrect' has an `@trustTypes` annotation, but no `@staticInterop` annotation.
diff --git a/tests/lib_2/js/trust_types_test.dart b/tests/lib_2/js/trust_types_test.dart
new file mode 100644
index 0000000..2cbfb37
--- /dev/null
+++ b/tests/lib_2/js/trust_types_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2022, 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.
+
+// Test that the [trustTypes] annotation has the same semantics as the older
+// style of js interop.
+
+import 'package:js/js.dart';
+import 'package:expect/expect.dart';
+
+class NonExistent {}
+
+@JS()
+@staticInterop
+@trustTypes
+class TrustMe {
+ external factory TrustMe();
+}
+
+extension TrustMeExtension on TrustMe {
+ external List<NonExistent> get foos;
+ external List<NonExistent> callFoos();
+ external List<NonExistent> callFoos1(int ignored);
+ external List<NonExistent> callFoos2(int ignored1, int ignored2);
+ external List<NonExistent> callFoos3(
+ int ignored1, int ignored2, int ignored3);
+ external List<NonExistent> callFoos4(
+ int ignored1, int ignored2, int ignored3, int ignored4);
+ external List<NonExistent> callFoos5(
+ int ignored1, int ignored2, int ignored3, int ignored4, int ignored5);
+ external String get fooPrimitive;
+}
+
+@JS()
+external void eval(String code);
+
+void main() {
+ eval(r'''
+ TrustMe = function TrustMe() {
+ this.foos = 'not a list 1';
+ this.fooPrimitive = 5;
+ this.callFoos = function() {
+ return 'not a list 2';
+ }
+ this.callFoos1 = function(a) {
+ return 'not a list 3';
+ }
+ this.callFoos2 = function(a, b) {
+ return 'not a list 4';
+ }
+ this.callFoos3 = function(a, b, c) {
+ return 'not a list 5';
+ }
+ this.callFoos4 = function(a, b, c, d) {
+ return 'not a list 6';
+ }
+ this.callFoos5 = function(a, b, c, d, e) {
+ return 'not a list 7';
+ }
+ }
+ ''');
+ final trusted = TrustMe();
+ Expect.equals('not a list 1', trusted.foos.toString());
+ Expect.equals('not a list 2', trusted.callFoos().toString());
+ Expect.equals('not a list 3', trusted.callFoos1(1).toString());
+ Expect.equals('not a list 4', trusted.callFoos2(1, 1).toString());
+ Expect.equals('not a list 5', trusted.callFoos3(1, 1, 1).toString());
+ Expect.equals('not a list 6', trusted.callFoos4(1, 1, 1, 1).toString());
+
+ final falseList = trusted.callFoos5(1, 1, 1, 1, 1);
+ Expect.equals('not a list 7', falseList.toString());
+ Expect.throws(() => falseList.removeAt(0));
+
+ final falseString = trusted.fooPrimitive;
+ Expect.equals(5, falseString);
+ Expect.throws(() => falseString.codeUnitAt(0));
+}
diff --git a/tests/lib_2/lib_2.status b/tests/lib_2/lib_2.status
index cb20d17..1feee84 100644
--- a/tests/lib_2/lib_2.status
+++ b/tests/lib_2/lib_2.status
@@ -12,7 +12,8 @@
isolate/issue_24243_parent_isolate_test: Skip # Requires checked mode
[ $runtime == d8 ]
-js/js_util/javascriptobject_extensions_test.dart: SkipByDesign # Uses dart:html.
+js/js_util/javascriptobject_extensions_test: SkipByDesign # Uses dart:html.
+js/static_interop_test/futurevaluetype_test: SkipByDesign # Uses dart:html.
[ $runtime == dart_precompiled ]
isolate/package_config_getter_test: SkipByDesign # AOT mode doesn't preserve package structure.
@@ -54,6 +55,7 @@
js/method_call_on_object_test: SkipByDesign # Issue 42085.
js/mock_test/*: SkipByDesign # Issue 42085.
js/parameters_test: SkipByDesign # Issue 42085.
+js/trust_types_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
[ $compiler != dart2js && $compiler != dartdevk ]
web/*: SkipByDesign
diff --git a/tests/modular/js_interop/modules.yaml b/tests/modular/js_interop/modules.yaml
index 79290b9..9e9b3b6 100644
--- a/tests/modular/js_interop/modules.yaml
+++ b/tests/modular/js_interop/modules.yaml
@@ -6,5 +6,6 @@
dependencies:
main: log
log: js
+ js: meta
packages:
js: ../../../pkg/js/lib
diff --git a/tests/modular/static_interop_erasure/modules.yaml b/tests/modular/static_interop_erasure/modules.yaml
index e356ba9..af71351 100644
--- a/tests/modular/static_interop_erasure/modules.yaml
+++ b/tests/modular/static_interop_erasure/modules.yaml
@@ -7,5 +7,6 @@
dependencies:
main: static_interop
static_interop: js
+ js: meta
packages:
js: ../../../pkg/js/lib
diff --git a/tests/modular/unused_library_and_module/main.dart b/tests/modular/unused_library_and_module/main.dart
new file mode 100644
index 0000000..b808acc
--- /dev/null
+++ b/tests/modular/unused_library_and_module/main.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, 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.
+
+import 'package:expect/expect.dart';
+
+import 'used_module/used_library.dart';
+
+main() {
+ Expect.equals(usedConstant, 1);
+}
diff --git a/tests/modular/unused_library_and_module/modules.yaml b/tests/modular/unused_library_and_module/modules.yaml
new file mode 100644
index 0000000..1e0c315
--- /dev/null
+++ b/tests/modular/unused_library_and_module/modules.yaml
@@ -0,0 +1,8 @@
+# Copyright (c) 2022, 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.
+#
+# Regression test: integral numbers should be treated as int and not double
+# after serialization across modules.
+dependencies:
+ main: [expect, used_module, unused_module]
diff --git a/tests/modular/unused_library_and_module/unused_module.dart b/tests/modular/unused_library_and_module/unused_module.dart
new file mode 100644
index 0000000..06d84dd
--- /dev/null
+++ b/tests/modular/unused_library_and_module/unused_module.dart
@@ -0,0 +1,4 @@
+// Copyright (c) 2022, 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.
+const int unusedConstant2 = 3;
diff --git a/tests/modular/unused_library_and_module/used_module/unused_library.dart b/tests/modular/unused_library_and_module/used_module/unused_library.dart
new file mode 100644
index 0000000..5b0b178
--- /dev/null
+++ b/tests/modular/unused_library_and_module/used_module/unused_library.dart
@@ -0,0 +1,4 @@
+// Copyright (c) 2022, 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.
+const int unusedConstant1 = 2;
diff --git a/tests/modular/unused_library_and_module/used_module/used_library.dart b/tests/modular/unused_library_and_module/used_module/used_library.dart
new file mode 100644
index 0000000..ea47365
--- /dev/null
+++ b/tests/modular/unused_library_and_module/used_module/used_library.dart
@@ -0,0 +1,4 @@
+// Copyright (c) 2022, 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.
+const int usedConstant = 1;
diff --git a/tests/web/js_trust_types_disallowed_test.dart b/tests/web/js_trust_types_disallowed_test.dart
new file mode 100644
index 0000000..13dd1c6
--- /dev/null
+++ b/tests/web/js_trust_types_disallowed_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2022, 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.
+
+import 'package:js/js.dart';
+
+@JS()
+@staticInterop
+@trustTypes
+class Incorrect {}
+// ^
+// [web] JS interop class 'Incorrect' has an `@trustTypes` annotation, but `@trustTypes` is only supported within the sdk.
diff --git a/tests/web_2/js_trust_types_disallowed_test.dart b/tests/web_2/js_trust_types_disallowed_test.dart
new file mode 100644
index 0000000..13dd1c6
--- /dev/null
+++ b/tests/web_2/js_trust_types_disallowed_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2022, 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.
+
+import 'package:js/js.dart';
+
+@JS()
+@staticInterop
+@trustTypes
+class Incorrect {}
+// ^
+// [web] JS interop class 'Incorrect' has an `@trustTypes` annotation, but `@trustTypes` is only supported within the sdk.
diff --git a/tools/VERSION b/tools/VERSION
index 370264a..d376cc8 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 40
+PRERELEASE 41
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 1feea04..459362c 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -1783,10 +1783,75 @@
},
"steps": [
{
- "name": "build dart x64",
+ "name": "build dart debug arm64",
"script": "tools/build.py",
"arguments": [
- "--mode=all",
+ "--mode=debug",
+ "--arch=arm64",
+ "--no-clang",
+ "--no-goma",
+ "dart_precompiled_runtime",
+ "gen_snapshot",
+ "runtime"
+ ]
+ },
+ {
+ "name": "build dart release arm64",
+ "script": "tools/build.py",
+ "arguments": [
+ "--mode=release",
+ "--arch=arm64",
+ "--no-clang",
+ "--no-goma",
+ "dart_precompiled_runtime",
+ "gen_snapshot",
+ "runtime"
+ ]
+ },
+ {
+ "name": "build dart product arm64",
+ "script": "tools/build.py",
+ "arguments": [
+ "--mode=product",
+ "--arch=arm64",
+ "--no-clang",
+ "--no-goma",
+ "dart_precompiled_runtime",
+ "gen_snapshot",
+ "runtime"
+ ]
+ },
+ {
+ "name": "build dart debug x64",
+ "script": "tools/build.py",
+ "arguments": [
+ "--mode=debug",
+ "--arch=x64",
+ "--no-clang",
+ "--no-goma",
+ "dart_precompiled_runtime",
+ "gen_snapshot",
+ "runtime"
+ ]
+ },
+ {
+ "name": "build dart release x64",
+ "script": "tools/build.py",
+ "arguments": [
+ "--mode=release",
+ "--arch=x64",
+ "--no-clang",
+ "--no-goma",
+ "dart_precompiled_runtime",
+ "gen_snapshot",
+ "runtime"
+ ]
+ },
+ {
+ "name": "build dart product x64",
+ "script": "tools/build.py",
+ "arguments": [
+ "--mode=product",
"--arch=x64",
"--no-clang",
"--no-goma",
@@ -3064,7 +3129,7 @@
"name": "build dart",
"script": "tools/build.py",
"arguments": [
- "--arch=ia32,x64",
+ "--arch=ia32,x64,arm64",
"--mode=release",
"--check-clean",
"create_sdk",
@@ -3075,7 +3140,7 @@
"name": "upload sdk",
"script": "tools/bots/dart_sdk.py",
"arguments": [
- "--arch=ia32,x64"
+ "--arch=ia32,x64,arm64"
]
}
]
diff --git a/tools/gn.py b/tools/gn.py
index f5c01ad..a40302a 100755
--- a/tools/gn.py
+++ b/tools/gn.py
@@ -67,61 +67,76 @@
return [merge(x, y) for x, y in gn_args.items()]
-# Runs true if the currently executing python interpreter is running under
-# Rosetta. I.e., python3 is an x64 executable and we're on an arm64 Mac.
-def IsRosetta():
- if platform.system() == 'Darwin':
- p = subprocess.Popen(['sysctl', '-in', 'sysctl.proc_translated'],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- output, _ = p.communicate()
- return output.decode('utf-8').strip() == '1'
- return False
-
-
+# The C compiler's host.
def HostCpuForArch(arch):
- # Check for Rosetta before checking platform.machine(), as the latter
- # returns 'x86_64' when running under Rosetta.
- if IsRosetta():
- if arch in ['x64', 'x64c']:
- # Without this case, we would try to build with
- # host_cpu="arm64"
- # target_cpu="x64"
- # dart_target_arch="x64"
- # Which requires the VM to use an x64 simulator in the host
- # arm64 binaries, and this simulator is unimplemented.
- return 'x64'
- else:
- return 'arm64'
-
- m = platform.machine()
- if m == 'aarch64' or m == 'arm64':
- return 'arm64'
- if m == 'armv7l':
- return 'arm'
-
- if arch in ['ia32', 'arm', 'simarm', 'simarm_x64', 'riscv32', 'simriscv32']:
- return 'x86'
- if arch in [
- 'x64', 'arm64', 'simarm64', 'arm_x64', 'x64c', 'arm64c',
- 'simarm64c', 'riscv64', 'simriscv64'
- ]:
+ if arch.endswith('_x64'):
return 'x64'
+ if arch.endswith('_arm64'):
+ return 'arm64'
+ if arch.endswith('_riscv64'):
+ return 'riscv64'
+
+ # For each target architecture, we prefer in descending order
+ # - using the same architecture for the host (supports all architectures)
+ # - using a host architecture with the same word size (supports arm and riscv, which have simulators)
+ # - using a host architecture with a different word size (supports only AOT and only 32-bit target on 64-bit host)
+ if arch in ['ia32']:
+ candidates = ['x86']
+ elif arch in ['x64', 'x64c']:
+ candidates = ['x64']
+ elif arch in ['arm', 'simarm']:
+ candidates = ['arm', 'x86', 'riscv32', 'arm64', 'x64', 'riscv64']
+ elif arch in ['arm64', 'arm64c', 'simarm64', 'simarm64c']:
+ candidates = ['arm64', 'x64', 'riscv64']
+ elif arch in ['riscv32', 'simriscv32']:
+ candidates = ['riscv32', 'arm', 'x86', 'riscv64', 'arm64', 'x64']
+ elif arch in ['riscv64', 'simriscv64']:
+ candidates = ['riscv64', 'arm64', 'x64']
+ else:
+ raise Exception("Unknown Dart architecture: %s" % arch)
+
+ available = utils.HostArchitectures()
+ for candidate in candidates:
+ if candidate in available:
+ return candidate
+
+ raise Exception(
+ "Failed to find a C host architecture for %s. Need one of %s but only %s are available."
+ % (arch, candidates, available))
# The C compiler's target.
def TargetCpuForArch(arch, target_os):
- if arch in ['ia32', 'simarm', 'simriscv32']:
+ # Real target architectures
+ if arch in ['ia32']:
return 'x86'
- if arch in [
- 'x64', 'simarm64', 'simarm_x64', 'simriscv64', 'x64c', 'simarm64c'
- ]:
+ elif arch in ['x64', 'x64c']:
return 'x64'
- if arch == 'arm_x64':
+ elif arch in ['arm', 'arm_x64', 'arm_arm64', 'arm_riscv64']:
return 'arm'
- if arch == 'arm64c':
+ elif arch in ['arm64', 'arm64c']:
return 'arm64'
- return arch
+ elif arch in ['riscv32', 'riscv32_x64', 'riscv32_arm64', 'riscv32_riscv64']:
+ return 'riscv32'
+ elif arch in ['riscv64']:
+ return 'riscv64'
+
+ # Simulators
+ if arch in ['simarm', 'simriscv32']:
+ candidates = ['arm', 'riscv32', 'x86']
+ elif arch in ['simarm64', 'simarm64c', 'simriscv64']:
+ candidates = ['arm64', 'riscv64', 'x64']
+ else:
+ raise Exception("Unknown Dart architecture: %s" % arch)
+
+ available = utils.HostArchitectures()
+ for candidate in candidates:
+ if candidate in available:
+ return candidate
+
+ raise Exception(
+ "Failed to find a C target architecture for %s. Need one of %s but only %s are available."
+ % (arch, candidates, available))
# The Dart compiler's target.
@@ -198,8 +213,9 @@
gn_args['dart_use_compressed_pointers'] = IsCompressedPointerArch(arch)
# Configure Crashpad library if it is used.
- gn_args['dart_use_crashpad'] = (args.use_crashpad or
- DART_USE_CRASHPAD in os.environ)
+ gn_args['dart_use_crashpad'] = ((args.use_crashpad or
+ DART_USE_CRASHPAD in os.environ) and
+ gn_args['target_cpu'] in ['x86', 'x64'])
if gn_args['dart_use_crashpad']:
# Tell Crashpad's BUILD files which checkout layout to use.
gn_args['crashpad_dependencies'] = 'dart'
diff --git a/tools/utils.py b/tools/utils.py
index 2f42263..6209073 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -67,9 +67,11 @@
'arm': 'arm',
'arm64': 'arm',
'arm_x64': 'arm',
+ 'arm_arm64': 'arm',
'simarm': 'ia32',
'simarm64': 'ia32',
'simarm_x64': 'ia32',
+ 'simarm_arm64': 'arm',
'x64c': 'ia32',
'arm64c': 'arm',
'simarm64c': 'ia32',
@@ -149,27 +151,44 @@
return None
+# Runs true if the currently executing python interpreter is running under
+# Rosetta. I.e., python3 is an x64 executable and we're on an arm64 Mac.
+def IsRosetta():
+ if platform.system() == 'Darwin':
+ p = subprocess.Popen(['sysctl', '-in', 'sysctl.proc_translated'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ output, _ = p.communicate()
+ return output.decode('utf-8').strip() == '1'
+ return False
+
+
+# Returns the architectures that can run on the current machine.
+def HostArchitectures():
+ m = platform.machine()
+ if platform.system() == 'Darwin':
+ if m == 'arm64' or IsRosetta():
+ # ARM64 Macs also support X64.
+ return ['arm64', 'x64']
+ if m == 'x86_64':
+ # X64 Macs no longer support IA32.
+ return ['x64']
+ else:
+ if m in ['aarch64', 'arm64', 'arm64e']:
+ return ['arm64']
+ if m in ['armv7l']:
+ return ['arm']
+ if m in ['i386', 'i686', 'ia32', 'x86']:
+ return ['x86']
+ if m in ['x64', 'x86-64', 'x86_64', 'AMD64']:
+ return ['x64', 'x86']
+ raise Exception('Failed to determine host architectures for %s %s',
+ platform.machine(), platform.system())
+
+
# Try to guess the host architecture.
def GuessArchitecture():
- os_id = platform.machine()
- if os_id.startswith('aarch64') or os_id == 'arm64':
- return 'arm64'
- elif os_id.startswith('arm'):
- return 'arm'
- elif '64' in os_id:
- return 'x64'
- elif (not os_id) or (not re.match('(x|i[3-6])86', os_id) is None):
- return 'ia32'
- elif os_id == 'i86pc':
- return 'ia32'
-
- guess_os = GuessOS()
- print('Warning: Guessing architecture {} based on os {}\n'.format(
- os_id, guess_os))
- if guess_os == 'win32':
- return 'ia32'
- return None
-
+ return HostArchitectures()[0]
# Try to guess the number of cpus on this machine.
def GuessCpus():
@@ -242,9 +261,15 @@
def IsCrossBuild(target_os, arch):
- host_arch = GuessArchitecture()
- return ((GetArchFamily(host_arch) != GetArchFamily(arch)) or
- (target_os != GuessOS()))
+ if target_os in [None, 'host']:
+ return False
+ if target_os != GuessOS():
+ return True
+ if arch.startswith('sim'):
+ return False
+ if arch in HostArchitectures():
+ return False
+ return True
def GetBuildConf(mode, arch, conf_os=None, sanitizer=None):
@@ -253,9 +278,8 @@
arch.upper())
# Ask for a cross build if the host and target architectures don't match.
- host_arch = GuessArchitecture()
cross_build = ''
- if GetArchFamily(host_arch) != GetArchFamily(arch):
+ if IsCrossBuild(conf_os, arch):
cross_build = 'X'
return '{}{}{}{}'.format(GetBuildMode(mode), GetBuildSanitizer(sanitizer),
cross_build, arch.upper())