[VM/runtime] - detect null safety before isolate initialization

- Detect null safety when not specified before isolate
      initialization
      - for source files by having CFE parse the source file
        for @dart annotations
      - for kernel files by sniffing the kernel file for
        compilation mode
      - for appJIT files by sniffing the feature string
      - for AOT snapshots by sniffing the feature string

    - Remove workaround of returning null safety to false during
      bootstrapping

    - Add a new Dart C API call for detecting null safety

Bug: 41766
Change-Id: Ia8cf264323a2d0d58c2855ce6491456aa6f1da07
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/150089
Commit-Queue: Siva Annamalai <asiva@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
asiva 2020-06-11 01:22:35 +00:00 committed by commit-bot@chromium.org
parent c0c66ab10f
commit a782dd82db
33 changed files with 886 additions and 337 deletions

View file

@ -28,7 +28,6 @@ import 'dart:isolate';
import 'dart:typed_data' show Uint8List;
import 'package:build_integration/file_system/multi_root.dart';
import 'package:front_end/src/api_prototype/experimental_flags.dart';
import 'package:front_end/src/api_prototype/front_end.dart' as fe
show CompilerResult;
import 'package:front_end/src/api_prototype/memory_file_system.dart';
@ -78,6 +77,7 @@ const int kTrainTag = 3;
const int kCompileExpressionTag = 4;
const int kListDependenciesTag = 5;
const int kNotifyIsolateShutdownTag = 6;
const int kDetectNullabilityTag = 7;
bool allowDartInternalImport = false;
@ -92,6 +92,62 @@ const int kNullSafetyOptionUnspecified = 0;
const int kNullSafetyOptionWeak = 1;
const int kNullSafetyOptionStrong = 2;
CompilerOptions setupCompilerOptions(
FileSystem fileSystem,
Uri platformKernelPath,
bool suppressWarnings,
bool enableAsserts,
int nullSafety,
List<String> experimentalFlags,
bool bytecode,
Uri packagesUri,
List<String> errors) {
final expFlags = <String>[];
if (experimentalFlags != null) {
for (String flag in experimentalFlags) {
expFlags.addAll(flag.split(","));
}
}
return new CompilerOptions()
..fileSystem = fileSystem
..target = new VmTarget(new TargetFlags(
enableNullSafety: nullSafety == kNullSafetyOptionStrong))
..packagesFileUri = packagesUri
..sdkSummary = platformKernelPath
..verbose = verbose
..omitPlatform = true
..bytecode = bytecode
..experimentalFlags = parseExperimentalFlags(
parseExperimentalArguments(expFlags),
onError: (msg) => errors.add(msg))
..environmentDefines = new EnvironmentMap()
..nnbdMode = (nullSafety == kNullSafetyOptionStrong)
? NnbdMode.Strong
: NnbdMode.Weak
..onDiagnostic = (DiagnosticMessage message) {
bool printMessage;
switch (message.severity) {
case Severity.error:
case Severity.internalProblem:
// TODO(sigmund): support emitting code with errors as long as they
// are handled in the generated code.
printMessage = false; // errors are printed by VM
errors.addAll(message.plainTextFormatted);
break;
case Severity.warning:
printMessage = !suppressWarnings;
break;
case Severity.context:
case Severity.ignored:
throw "Unexpected severity: ${message.severity}";
}
if (printMessage) {
printDiagnosticMessage(message, stderr.writeln);
}
};
}
abstract class Compiler {
final int isolateId;
final FileSystem fileSystem;
@ -135,50 +191,16 @@ abstract class Compiler {
print("DFE: platformKernelPath: ${platformKernelPath}");
}
var expFlags = List<String>();
if (experimentalFlags != null) {
for (String flag in experimentalFlags) {
expFlags.addAll(flag.split(","));
}
}
options = new CompilerOptions()
..fileSystem = fileSystem
..target = new VmTarget(new TargetFlags(
enableNullSafety: nullSafety == kNullSafetyOptionStrong))
..packagesFileUri = packagesUri
..sdkSummary = platformKernelPath
..verbose = verbose
..omitPlatform = true
..bytecode = bytecode
..experimentalFlags = parseExperimentalFlags(
parseExperimentalArguments(expFlags),
onError: (msg) => errors.add(msg))
..environmentDefines = new EnvironmentMap()
..nnbdMode = (nullSafety == kNullSafetyOptionStrong)
? NnbdMode.Strong
: NnbdMode.Weak
..onDiagnostic = (DiagnosticMessage message) {
bool printMessage;
switch (message.severity) {
case Severity.error:
case Severity.internalProblem:
// TODO(sigmund): support emitting code with errors as long as they
// are handled in the generated code.
printMessage = false; // errors are printed by VM
errors.addAll(message.plainTextFormatted);
break;
case Severity.warning:
printMessage = !suppressWarnings;
break;
case Severity.context:
case Severity.ignored:
throw "Unexpected severity: ${message.severity}";
}
if (printMessage) {
printDiagnosticMessage(message, stderr.writeln);
}
};
options = setupCompilerOptions(
fileSystem,
platformKernelPath,
suppressWarnings,
enableAsserts,
nullSafety,
experimentalFlags,
bytecode,
packagesUri,
errors);
}
Future<CompilerResult> compile(Uri script) {
@ -352,13 +374,6 @@ class IncrementalCompilerWrapper extends Compiler {
@override
Future<CompilerResult> compileInternal(Uri script) async {
if (generator == null) {
if ((nullSafety == kNullSafetyOptionUnspecified) &&
options.experimentalFlags[ExperimentalFlag.nonNullable]) {
await autoDetectNullSafetyMode(script, options);
// Reinitialize target to set correct null safety mode.
options.target = new VmTarget(new TargetFlags(
enableNullSafety: options.nnbdMode == NnbdMode.Strong));
}
generator = new IncrementalCompiler(options, script);
}
errors.clear();
@ -420,13 +435,6 @@ class SingleShotCompilerWrapper extends Compiler {
@override
Future<CompilerResult> compileInternal(Uri script) async {
if ((nullSafety == kNullSafetyOptionUnspecified) &&
options.experimentalFlags[ExperimentalFlag.nonNullable]) {
await autoDetectNullSafetyMode(script, options);
// Reinitialize target to set correct null safety mode.
options.target = new VmTarget(new TargetFlags(
enableNullSafety: options.nnbdMode == NnbdMode.Strong));
}
fe.CompilerResult compilerResult = requireMain
? await kernelForProgram(script, options)
: await kernelForModule([script], options);
@ -768,6 +776,7 @@ Future _processLoadRequest(request) async {
final String packageConfig = request[12];
final String multirootFilepaths = request[13];
final String multirootScheme = request[14];
final String workingDirectory = request[15];
Uri platformKernelPath = null;
List<int> platformKernel = null;
@ -810,6 +819,30 @@ Future _processLoadRequest(request) async {
}
port.send(new CompilationResult.ok(null).toResponse());
return;
} else if (tag == kDetectNullabilityTag) {
FileSystem fileSystem = _buildFileSystem(
sourceFiles, platformKernel, multirootFilepaths, multirootScheme);
Uri packagesUri = null;
if (packageConfig != null) {
packagesUri = Uri.parse(packageConfig);
} else if (Platform.packageConfig != null) {
packagesUri = Uri.parse(Platform.packageConfig);
}
if (packagesUri != null && packagesUri.scheme == '') {
// Script does not have a scheme, assume that it is a path,
// resolve it against the working directory.
packagesUri = Uri.directory(workingDirectory).resolveUri(packagesUri);
}
final List<String> errors = <String>[];
var options = setupCompilerOptions(fileSystem, platformKernelPath, false,
false, nullSafety, experimentalFlags, false, packagesUri, errors);
// script should only be null for kUpdateSourcesTag.
assert(script != null);
await autoDetectNullSafetyMode(script, options);
bool value = options.nnbdMode == NnbdMode.Strong;
port.send(new CompilationResult.nullSafety(value).toResponse());
return;
}
// script should only be null for kUpdateSourcesTag.
@ -997,6 +1030,7 @@ Future trainInternal(
null /* package_config */,
null /* multirootFilepaths */,
null /* multirootScheme */,
null /* original working directory */,
];
await _processLoadRequest(request);
}
@ -1044,6 +1078,8 @@ abstract class CompilationResult {
factory CompilationResult.ok(Uint8List bytes) = _CompilationOk;
factory CompilationResult.nullSafety(bool val) = _CompilationNullSafety;
factory CompilationResult.errors(List<String> errors, Uint8List bytes) =
_CompilationError;
@ -1075,6 +1111,20 @@ class _CompilationOk extends CompilationResult {
String toString() => "_CompilationOk(${bytes.length} bytes)";
}
class _CompilationNullSafety extends CompilationResult {
final bool _null_safety;
_CompilationNullSafety(this._null_safety) : super._() {}
@override
Status get status => Status.ok;
@override
get payload => _null_safety;
String toString() => "_CompilationNullSafety($_null_safety)";
}
abstract class _CompilationFail extends CompilationResult {
_CompilationFail() : super._();

View file

@ -4,8 +4,6 @@
#include "bin/dfe.h"
#include <memory>
#include "bin/abi_version.h"
#include "bin/dartutils.h"
#include "bin/directory.h"
@ -191,53 +189,54 @@ bool DFE::CanUseDartFrontend() const {
(KernelServiceDillAvailable() || (frontend_filename() != nullptr));
}
class WindowsPathSanitizer {
public:
explicit WindowsPathSanitizer(const char* path) {
// For Windows we need to massage the paths a bit according to
// http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx
//
// Convert
// C:\one\two\three
// to
// /C:/one/two/three
//
// (see builtin.dart#_sanitizeWindowsPath)
intptr_t len = strlen(path);
sanitized_uri_ = reinterpret_cast<char*>(malloc(len + 1 + 1));
if (sanitized_uri_ == nullptr) {
OUT_OF_MEMORY();
}
char* s = sanitized_uri_;
if (len > 2 && path[1] == ':') {
*s++ = '/';
}
for (const char* p = path; *p != '\0'; ++p, ++s) {
*s = *p == '\\' ? '/' : *p;
}
*s = '\0';
PathSanitizer::PathSanitizer(const char* path) {
#if defined(HOST_OS_WINDOWS)
// For Windows we need to massage the paths a bit according to
// http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx
//
// Convert
// C:\one\two\three
// to
// /C:/one/two/three
//
// (see builtin.dart#_sanitizeWindowsPath)
if (path == nullptr) {
return;
}
~WindowsPathSanitizer() { free(sanitized_uri_); }
intptr_t len = strlen(path);
char* uri = reinterpret_cast<char*>(new char[len + 1 + 1]);
if (uri == nullptr) {
OUT_OF_MEMORY();
}
char* s = uri;
if (len > 2 && path[1] == ':') {
*s++ = '/';
}
for (const char* p = path; *p != '\0'; ++p, ++s) {
*s = *p == '\\' ? '/' : *p;
}
*s = '\0';
sanitized_uri_ = std::unique_ptr<char[]>(uri);
#else
sanitized_uri_ = path;
#endif // defined(HOST_OS_WINDOWS)
}
const char* sanitized_uri() { return sanitized_uri_; }
private:
char* sanitized_uri_;
DISALLOW_COPY_AND_ASSIGN(WindowsPathSanitizer);
};
const char* PathSanitizer::sanitized_uri() const {
#if defined(HOST_OS_WINDOWS)
return sanitized_uri_.get();
#else
return sanitized_uri_;
#endif // defined(HOST_OS_WINDOWS)
}
Dart_KernelCompilationResult DFE::CompileScript(const char* script_uri,
bool incremental,
const char* package_config) {
// TODO(aam): When Frontend is ready, VM should be passing vm_outline.dill
// instead of vm_platform.dill to Frontend for compilation.
#if defined(HOST_OS_WINDOWS)
WindowsPathSanitizer path_sanitizer(script_uri);
PathSanitizer path_sanitizer(script_uri);
const char* sanitized_uri = path_sanitizer.sanitized_uri();
#else
const char* sanitized_uri = script_uri;
#endif
return Dart_CompileToKernel(
sanitized_uri, platform_strong_dill_for_compilation_,

View file

@ -5,6 +5,8 @@
#ifndef RUNTIME_BIN_DFE_H_
#define RUNTIME_BIN_DFE_H_
#include <memory>
#include "include/dart_api.h"
#include "include/dart_native_api.h"
#include "platform/assert.h"
@ -121,6 +123,21 @@ class DFE {
DISALLOW_COPY_AND_ASSIGN(DFE);
};
class PathSanitizer {
public:
explicit PathSanitizer(const char* path);
const char* sanitized_uri() const;
private:
#if defined(HOST_OS_WINDOWS)
std::unique_ptr<char[]> sanitized_uri_;
#else
const char* sanitized_uri_;
#endif // defined(HOST_OS_WINDOWS)
DISALLOW_COPY_AND_ASSIGN(PathSanitizer);
};
#if !defined(DART_PRECOMPILED_RUNTIME)
extern DFE dfe;
#endif

View file

@ -664,6 +664,9 @@ static int CreateIsolateAndSnapshot(const CommandLineOptions& inputs) {
Dart_IsolateFlags isolate_flags;
Dart_IsolateFlagsInitialize(&isolate_flags);
isolate_flags.null_safety =
Dart_DetectNullSafety(nullptr, nullptr, nullptr, nullptr, nullptr,
kernel_buffer, kernel_buffer_size);
if (IsSnapshottingForPrecompilation()) {
isolate_flags.obfuscate = obfuscate;
isolate_flags.entry_points = no_entry_points;

View file

@ -599,6 +599,9 @@ static Dart_Isolate CreateIsolateGroupAndSetupHelper(
const uint8_t* isolate_snapshot_data = app_isolate_snapshot_data;
const uint8_t* isolate_snapshot_instructions =
app_isolate_snapshot_instructions;
flags->null_safety =
Dart_DetectNullSafety(nullptr, nullptr, nullptr, isolate_snapshot_data,
isolate_snapshot_instructions, nullptr, -1);
#else
// JIT: Main isolate starts from the app snapshot, if any. Other isolates
// use the core libraries snapshot.
@ -635,6 +638,13 @@ static Dart_Isolate CreateIsolateGroupAndSetupHelper(
if (kernel_buffer == NULL && !isolate_run_app_snapshot) {
dfe.ReadScript(script_uri, &kernel_buffer, &kernel_buffer_size);
}
PathSanitizer script_uri_sanitizer(script_uri);
PathSanitizer packages_config_sanitizer(packages_config);
flags->null_safety = Dart_DetectNullSafety(
script_uri_sanitizer.sanitized_uri(),
packages_config_sanitizer.sanitized_uri(),
DartUtils::original_working_directory, isolate_snapshot_data,
isolate_snapshot_instructions, kernel_buffer, kernel_buffer_size);
#endif // !defined(DART_PRECOMPILED_RUNTIME)
auto isolate_group_data = new IsolateGroupData(

View file

@ -532,6 +532,7 @@ typedef struct {
Dart_QualifiedFunctionName* entry_points;
bool load_vmservice_library;
bool copy_parent_code;
bool null_safety;
} Dart_IsolateFlags;
/**
@ -3313,8 +3314,8 @@ typedef enum {
typedef struct {
Dart_KernelCompilationStatus status;
bool null_safety;
char* error;
uint8_t* kernel;
intptr_t kernel_size;
} Dart_KernelCompilationResult;
@ -3370,6 +3371,49 @@ DART_EXPORT void Dart_SetDartLibrarySourcesKernel(
const uint8_t* platform_kernel,
const intptr_t platform_kernel_size);
/**
* Detect the null safety opt-in status.
*
* When running from source, it is based on the opt-in status of `script_uri`.
* When running from a kernel buffer, it is based on the mode used when
* generating `kernel_buffer`.
* When running from an appJIT or AOT snapshot, it is based on the mode used
* when generating `snapshot_data`.
*
* \param script_uri Uri of the script that contains the source code
*
* \param package_config Uri of the package configuration file (either in format
* of .packages or .dart_tool/package_config.json) for the null safety
* detection to resolve package imports against. If this parameter is not
* passed the package resolution of the parent isolate should be used.
*
* \param original_working_directory current working directory when the VM
* process was launched, this is used to correctly resolve the path specified
* for package_config.
*
* \param snapshot_data
*
* \param snapshot_instructions Buffers containing a snapshot of the
* isolate or NULL if no snapshot is provided. If provided, the buffers must
* remain valid until the isolate shuts down.
*
* \param kernel_buffer
*
* \param kernel_buffer_size A buffer which contains a kernel/DIL program. Must
* remain valid until isolate shutdown.
*
* \return Returns true if the null safety is opted in by the input being
* run `script_uri`, `snapshot_data` or `kernel_buffer`.
*
*/
DART_EXPORT bool Dart_DetectNullSafety(const char* script_uri,
const char* package_config,
const char* original_working_directory,
const uint8_t* snapshot_data,
const uint8_t* snapshot_instructions,
const uint8_t* kernel_buffer,
intptr_t kernel_buffer_size);
#define DART_KERNEL_ISOLATE_NAME "kernel-service"
/*

View file

@ -109,7 +109,6 @@ static ErrorPtr BootstrapFromKernel(Thread* thread,
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
program->AutoDetectNullSafety(thread->isolate());
kernel::KernelLoader loader(program.get(), /*uri_to_source_table=*/nullptr);
Isolate* isolate = thread->isolate();

View file

@ -6662,23 +6662,50 @@ char* SnapshotHeaderReader::InitializeGlobalVMFlagsFromSnapshot(
#undef CHECK_FLAG
#undef SET_FLAG
if (FLAG_null_safety == kNullSafetyOptionUnspecified) {
if (strncmp(cursor, "null-safety", end - cursor) == 0) {
FLAG_null_safety = kNullSafetyOptionStrong;
cursor = end;
continue;
}
if (strncmp(cursor, "no-null-safety", end - cursor) == 0) {
FLAG_null_safety = kNullSafetyOptionWeak;
cursor = end;
continue;
}
cursor = end;
}
return nullptr;
}
bool SnapshotHeaderReader::NullSafetyFromSnapshot(const Snapshot* snapshot) {
bool null_safety = false;
SnapshotHeaderReader header_reader(snapshot);
const char* features = nullptr;
intptr_t features_length = 0;
char* error = header_reader.ReadFeatures(&features, &features_length);
if (error != nullptr) {
return false;
}
ASSERT(features[features_length] == '\0');
const char* cursor = features;
while (*cursor != '\0') {
while (*cursor == ' ') {
cursor++;
}
const char* end = strstr(cursor, " ");
if (end == nullptr) {
end = features + features_length;
}
if (strncmp(cursor, "null-safety", end - cursor) == 0) {
cursor = end;
null_safety = true;
continue;
}
if (strncmp(cursor, "no-null-safety", end - cursor) == 0) {
cursor = end;
null_safety = false;
continue;
}
cursor = end;
}
return nullptr;
return null_safety;
}
ApiErrorPtr FullSnapshotReader::ReadVMSnapshot() {

View file

@ -514,6 +514,7 @@ struct SerializerWritingObjectScope {
class SnapshotHeaderReader {
public:
static char* InitializeGlobalVMFlagsFromSnapshot(const Snapshot* snapshot);
static bool NullSafetyFromSnapshot(const Snapshot* snapshot);
explicit SnapshotHeaderReader(const Snapshot* snapshot)
: SnapshotHeaderReader(snapshot->kind(),

View file

@ -746,6 +746,55 @@ ErrorPtr Dart::InitIsolateFromSnapshot(Thread* T,
return Error::null();
}
bool Dart::DetectNullSafety(const char* script_uri,
const uint8_t* snapshot_data,
const uint8_t* snapshot_instructions,
const uint8_t* kernel_buffer,
intptr_t kernel_buffer_size,
const char* package_config,
const char* original_working_directory) {
// Before creating the isolate we first determine the null safety mode
// in which the isolate needs to run based on one of these factors :
// - if loading from source, based on opt-in status of the source
// - if loading from a kernel file, based on the mode used when
// generating the kernel file
// - if loading from an appJIT or AOT snapshot, based on the mode used
// when generating the snapshot.
ASSERT(FLAG_null_safety == kNullSafetyOptionUnspecified);
// If snapshot is an appJIT/AOT snapshot we will figure out the mode by
// sniffing the feature string in the snapshot.
if (snapshot_data != nullptr) {
// Read the snapshot and check for null safety option.
const Snapshot* snapshot = Snapshot::SetupFromBuffer(snapshot_data);
if (Snapshot::IncludesCode(snapshot->kind())) {
return SnapshotHeaderReader::NullSafetyFromSnapshot(snapshot);
}
}
#if !defined(DART_PRECOMPILED_RUNTIME)
// If kernel_buffer is specified, it could be a self contained
// kernel file or the kernel file of the application,
// figure out the null safety mode by sniffing the kernel file.
if (kernel_buffer != nullptr) {
const char* error = nullptr;
std::unique_ptr<kernel::Program> program = kernel::Program::ReadFromBuffer(
kernel_buffer, kernel_buffer_size, &error);
if (program != nullptr) {
return program->compilation_mode() == NNBDCompiledMode::kStrong;
}
return false;
}
// If we are loading from source, figure out the mode from the source.
if (KernelIsolate::GetExperimentalFlag("non-nullable")) {
return KernelIsolate::DetectNullSafety(script_uri, package_config,
original_working_directory);
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
return false;
}
#if defined(DART_PRECOMPILED_RUNTIME)
static void PrintLLVMConstantPool(Thread* T, Isolate* I) {
StackZone printing_zone(T);

View file

@ -66,6 +66,15 @@ class Dart : public AllStatic {
const uint8_t* snapshot_instructions,
const uint8_t* kernel_buffer,
intptr_t kernel_buffer_size);
static bool DetectNullSafety(const char* script_uri,
const uint8_t* snapshot_data,
const uint8_t* snapshot_instructions,
const uint8_t* kernel_buffer,
intptr_t kernel_buffer_size,
const char* package_config,
const char* original_working_directory);
static void RunShutdownCallback();
static void ShutdownIsolate(Isolate* isolate);
static void ShutdownIsolate();

View file

@ -5449,7 +5449,6 @@ DART_EXPORT Dart_Handle Dart_LoadScriptFromKernel(const uint8_t* buffer,
if (program == nullptr) {
return Api::NewError("Can't load Kernel binary: %s.", error);
}
program->AutoDetectNullSafety(I);
const Object& tmp = kernel::KernelLoader::LoadEntireProgram(program.get());
program.reset();
@ -5755,7 +5754,6 @@ DART_EXPORT Dart_Handle Dart_LoadLibraryFromKernel(const uint8_t* buffer,
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
StackZone zone(T);
Isolate* I = T->isolate();
CHECK_CALLBACK_STATE(T);
@ -5772,7 +5770,6 @@ DART_EXPORT Dart_Handle Dart_LoadLibraryFromKernel(const uint8_t* buffer,
if (program == nullptr) {
return Api::NewError("Can't load Kernel binary: %s.", error);
}
program->AutoDetectNullSafety(I);
const Object& result =
kernel::KernelLoader::LoadEntireProgram(program.get(), false);
program.reset();
@ -6028,6 +6025,24 @@ DART_EXPORT void Dart_SetDartLibrarySourcesKernel(
#endif
}
DART_EXPORT bool Dart_DetectNullSafety(const char* script_uri,
const char* package_config,
const char* original_working_directory,
const uint8_t* snapshot_data,
const uint8_t* snapshot_instructions,
const uint8_t* kernel_buffer,
intptr_t kernel_buffer_size) {
bool null_safety;
if (FLAG_null_safety == kNullSafetyOptionUnspecified) {
null_safety = Dart::DetectNullSafety(
script_uri, snapshot_data, snapshot_instructions, kernel_buffer,
kernel_buffer_size, package_config, original_working_directory);
} else {
null_safety = (FLAG_null_safety == kNullSafetyOptionStrong);
}
return null_safety;
}
// --- Service support ---
DART_EXPORT bool Dart_IsServiceIsolate(Dart_Isolate isolate) {

View file

@ -1455,6 +1455,7 @@ void Isolate::FlagsInitialize(Dart_IsolateFlags* api_flags) {
api_flags->entry_points = NULL;
api_flags->load_vmservice_library = false;
api_flags->copy_parent_code = false;
api_flags->null_safety = false;
}
void Isolate::FlagsCopyTo(Dart_IsolateFlags* api_flags) const {
@ -1466,6 +1467,7 @@ void Isolate::FlagsCopyTo(Dart_IsolateFlags* api_flags) const {
api_flags->entry_points = NULL;
api_flags->load_vmservice_library = should_load_vmservice();
api_flags->copy_parent_code = false;
api_flags->null_safety = null_safety();
}
void Isolate::FlagsCopyFrom(const Dart_IsolateFlags& api_flags) {
@ -1495,6 +1497,7 @@ void Isolate::FlagsCopyFrom(const Dart_IsolateFlags& api_flags) {
#undef SET_FROM_FLAG
set_should_load_vmservice(api_flags.load_vmservice_library);
set_null_safety(api_flags.null_safety);
// Copy entry points list.
ASSERT(embedder_entry_points_ == NULL);
@ -1757,26 +1760,12 @@ Isolate* Isolate::InitIsolate(const char* name_prefix,
isolate_group->RegisterIsolate(result);
if (ServiceIsolate::NameEquals(name_prefix)) {
// For now the service isolate always runs in weak mode.
result->set_null_safety(false);
ASSERT(!ServiceIsolate::Exists());
ServiceIsolate::SetServiceIsolate(result);
#if !defined(DART_PRECOMPILED_RUNTIME)
} else if (KernelIsolate::NameEquals(name_prefix)) {
// For now the kernel isolate always runs in weak mode.
result->set_null_safety(false);
ASSERT(!KernelIsolate::Exists());
KernelIsolate::SetKernelIsolate(result);
#endif // !defined(DART_PRECOMPILED_RUNTIME)
} else if (FLAG_null_safety != kNullSafetyOptionUnspecified) {
// If the null-safety option is specified on the command line then
// use the value specified on the command line, if the dill file being
// loaded is in a different mode than that specified on the command line
// we will get an error during kernel file loading.
result->set_null_safety(FLAG_null_safety == kNullSafetyOptionStrong);
#if !defined(DART_PRECOMPILED_RUNTIME)
} else if (!KernelIsolate::GetExperimentalFlag("non-nullable")) {
result->set_null_safety(false);
#endif // !defined(DART_PRECOMPILED_RUNTIME)
}

View file

@ -1235,11 +1235,6 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry<Isolate> {
}
bool null_safety() const {
// TODO(asiva) : We return false when the null safety mode is not yet set
// instead of just asserting as some code runs during bootstrapping that
// requires the mode to be set. Once all of that is resolved this could
// turn into just an assert.
if (null_safety_not_set()) return false;
ASSERT(!null_safety_not_set());
return NullSafetyBit::decode(isolate_flags_);
}

View file

@ -95,9 +95,6 @@ class Program {
intptr_t library_count() { return library_count_; }
NNBDCompiledMode compilation_mode() const { return compilation_mode_; }
// Detect null-safety mode from this program if it was not set yet.
void AutoDetectNullSafety(Isolate* isolate);
private:
Program() : typed_data_(NULL), kernel_data_(NULL), kernel_data_size_(-1) {}

View file

@ -226,20 +226,6 @@ std::unique_ptr<Program> Program::ReadFromTypedData(
return kernel::Program::ReadFrom(&reader, error);
}
void Program::AutoDetectNullSafety(Isolate* isolate) {
if (isolate->is_service_isolate() || isolate->is_kernel_isolate()) {
// For now the service isolate and kernel isolate will be running in
// weak mode and we assert for that here.
ASSERT(!isolate->null_safety());
} else {
// If null safety is not specified on the command line we use the value
// from the dill file that the CFE has computed based on how it was invoked.
if (FLAG_null_safety == kNullSafetyOptionUnspecified) {
isolate->set_null_safety(compilation_mode() == NNBDCompiledMode::kStrong);
}
}
}
} // namespace kernel
} // namespace dart
#endif // !defined(DART_PRECOMPILED_RUNTIME)

View file

@ -15,6 +15,7 @@
#include "vm/message_handler.h"
#include "vm/native_arguments.h"
#include "vm/native_entry.h"
#include "vm/native_message_handler.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/port.h"
@ -52,6 +53,10 @@ DEFINE_FLAG(charp,
// 1 - Update in-memory file system with in-memory sources (used by tests).
// 2 - Accept last compilation result.
// 3 - APP JIT snapshot training run for kernel_service.
// 4 - Compile expressions in context (used by expression evaluation).
// 5 - Generate dependencies used to create a dependencies file.
// 6 - Triggers shutdown of the kernel isolate.
// 7 - Detects the nullability of a script based on it's opt-in status.
const int KernelIsolate::kCompileTag = 0;
const int KernelIsolate::kUpdateSourcesTag = 1;
const int KernelIsolate::kAcceptTag = 2;
@ -59,6 +64,7 @@ const int KernelIsolate::kTrainTag = 3;
const int KernelIsolate::kCompileExpressionTag = 4;
const int KernelIsolate::kListDependenciesTag = 5;
const int KernelIsolate::kNotifyIsolateShutdown = 6;
const int KernelIsolate::kDetectNullabilityTag = 7;
const char* KernelIsolate::kName = DART_KERNEL_ISOLATE_NAME;
Dart_IsolateGroupCreateCallback KernelIsolate::create_group_callback_ = NULL;
@ -695,7 +701,8 @@ class KernelCompilationRequest : public ValueObject {
const char* package_config,
const char* multiroot_filepaths,
const char* multiroot_scheme,
const MallocGrowableArray<char*>* experimental_flags) {
const MallocGrowableArray<char*>* experimental_flags,
const char* original_working_directory) {
// Build the message for the Kernel isolate.
// tag is used to specify which operation the frontend should perform.
Dart_CObject tag;
@ -767,7 +774,10 @@ class KernelCompilationRequest : public ValueObject {
Dart_CObject null_safety;
null_safety.type = Dart_CObject_kInt32;
null_safety.value.as_int32 = FLAG_null_safety;
null_safety.value.as_int32 =
(isolate != NULL) ? (isolate->null_safety() ? kNullSafetyOptionStrong
: kNullSafetyOptionWeak)
: FLAG_null_safety;
intptr_t num_experimental_flags = experimental_flags->length();
Dart_CObject** experimental_flags_array =
@ -822,6 +832,17 @@ class KernelCompilationRequest : public ValueObject {
}
}
Dart_CObject original_working_directory_object;
{
if (original_working_directory != NULL) {
original_working_directory_object.type = Dart_CObject_kString;
original_working_directory_object.value.as_string =
const_cast<char*>(original_working_directory);
} else {
original_working_directory_object.type = Dart_CObject_kNull;
}
}
Dart_CObject* message_arr[] = {&tag,
&send_port,
&uri,
@ -836,7 +857,8 @@ class KernelCompilationRequest : public ValueObject {
&bytecode,
&package_config_uri,
&multiroot_filepaths_object,
&multiroot_scheme_object};
&multiroot_scheme_object,
&original_working_directory_object};
message.value.as_array.values = message_arr;
message.value.as_array.length = ARRAY_SIZE(message_arr);
// Send the message.
@ -862,11 +884,16 @@ class KernelCompilationRequest : public ValueObject {
private:
void LoadKernelFromResponse(Dart_CObject* response) {
ASSERT((response->type == Dart_CObject_kTypedData) ||
(response->type == Dart_CObject_kBool) ||
(response->type == Dart_CObject_kNull));
if (response->type == Dart_CObject_kNull) {
return;
}
if (response->type == Dart_CObject_kBool) {
result_.null_safety = response->value.as_bool;
return;
}
ASSERT(response->value.as_typed_data.type == Dart_TypedData_kUint8);
result_.kernel_size = response->value.as_typed_data.length;
@ -999,7 +1026,33 @@ Dart_KernelCompilationResult KernelIsolate::CompileToKernel(
kCompileTag, kernel_port, script_uri, platform_kernel,
platform_kernel_size, source_file_count, source_files,
incremental_compile, package_config, multiroot_filepaths,
multiroot_scheme, experimental_flags_);
multiroot_scheme, experimental_flags_, NULL);
}
bool KernelIsolate::DetectNullSafety(const char* script_uri,
const char* package_config,
const char* original_working_directory) {
// Start the kernel Isolate if it is not already running.
if (!Start()) {
Dart_KernelCompilationResult result = {};
result.status = Dart_KernelCompilationStatus_Unknown;
result.error = strdup("Error while starting Kernel isolate task");
return false;
}
// Wait for Kernel isolate to finish initialization.
Dart_Port kernel_port = WaitForKernelPort();
if (kernel_port == ILLEGAL_PORT) {
Dart_KernelCompilationResult result = {};
result.status = Dart_KernelCompilationStatus_Unknown;
result.error = strdup("Error while initializing Kernel isolate");
return false;
}
KernelCompilationRequest request;
Dart_KernelCompilationResult result = request.SendAndWaitForResponse(
kDetectNullabilityTag, kernel_port, script_uri, nullptr, -1, 0, nullptr,
false, package_config, nullptr, nullptr, experimental_flags_,
original_working_directory);
return result.null_safety;
}
Dart_KernelCompilationResult KernelIsolate::ListDependencies() {
@ -1014,7 +1067,7 @@ Dart_KernelCompilationResult KernelIsolate::ListDependencies() {
KernelCompilationRequest request;
return request.SendAndWaitForResponse(kListDependenciesTag, kernel_port, NULL,
NULL, 0, 0, NULL, false, NULL, NULL,
NULL, experimental_flags_);
NULL, experimental_flags_, NULL);
}
Dart_KernelCompilationResult KernelIsolate::AcceptCompilation() {
@ -1031,7 +1084,7 @@ Dart_KernelCompilationResult KernelIsolate::AcceptCompilation() {
KernelCompilationRequest request;
return request.SendAndWaitForResponse(kAcceptTag, kernel_port, NULL, NULL, 0,
0, NULL, true, NULL, NULL, NULL,
experimental_flags_);
experimental_flags_, NULL);
}
Dart_KernelCompilationResult KernelIsolate::CompileExpressionToKernel(
@ -1073,7 +1126,7 @@ Dart_KernelCompilationResult KernelIsolate::UpdateInMemorySources(
KernelCompilationRequest request;
return request.SendAndWaitForResponse(
kUpdateSourcesTag, kernel_port, NULL, NULL, 0, source_files_count,
source_files, true, NULL, NULL, NULL, experimental_flags_);
source_files, true, NULL, NULL, NULL, experimental_flags_, NULL);
}
void KernelIsolate::NotifyAboutIsolateShutdown(const Isolate* isolate) {

View file

@ -30,6 +30,7 @@ class KernelIsolate : public AllStatic {
static const int kCompileExpressionTag;
static const int kListDependenciesTag;
static const int kNotifyIsolateShutdown;
static const int kDetectNullabilityTag;
static void InitializeState();
static bool Start();
@ -53,6 +54,10 @@ class KernelIsolate : public AllStatic {
const char* multiroot_filepaths = NULL,
const char* multiroot_scheme = NULL);
static bool DetectNullSafety(const char* script_uri,
const char* package_config,
const char* original_working_directory);
static Dart_KernelCompilationResult AcceptCompilation();
static Dart_KernelCompilationResult UpdateInMemorySources(
int source_files_count,

View file

@ -78,16 +78,20 @@ VMTag::TagEntry VMTag::entries_[] = {
VMTagScope::VMTagScope(Thread* thread, uword tag, bool conditional_set)
: ThreadStackResource(thread) {
ASSERT(isolate_group() != NULL);
previous_tag_ = thread->vm_tag();
if (conditional_set) {
thread->set_vm_tag(tag);
if (thread != NULL) {
ASSERT(isolate_group() != NULL);
previous_tag_ = thread->vm_tag();
if (conditional_set) {
thread->set_vm_tag(tag);
}
}
}
VMTagScope::~VMTagScope() {
ASSERT(isolate_group() != NULL);
thread()->set_vm_tag(previous_tag_);
if (thread() != NULL) {
ASSERT(isolate_group() != NULL);
thread()->set_vm_tag(previous_tag_);
}
}
VMTagCounters::VMTagCounters() {

View file

@ -0,0 +1,39 @@
// Copyright (c) 2020, 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:io";
import "detect_nullsafety_helper.dart";
void main() {
// Create temporary directory.
var tmpDir = Directory.systemTemp.createTempSync();
var tmpDirPath = tmpDir.path;
String sourcePath = "$tmpDirPath/strong.dart";
String dillPath = "$tmpDirPath/strong.dill";
String jitPath = "$tmpDirPath/strong.appjit";
// Generate code for an isolate to run in strong mode.
generateIsolateSource(sourcePath, "");
generateKernel(sourcePath, dillPath);
generateAppJIT(sourcePath, jitPath);
try {
// Running from Source.
testNullSafetyMode(sourcePath, 'Strong Mode');
// Without the enable experiment option it will be in weak mode.
testNullSafetyMode1(sourcePath, 'Weak Mode');
// Running from Kernel File.
testNullSafetyMode(dillPath, 'Strong Mode');
// Without the enable experiment option it will be inferred to strong.
testNullSafetyMode1(dillPath, 'Strong Mode');
// Running from app JIT File.
testNullSafetyMode(jitPath, 'Strong Mode');
// Without the enable experiment option it will be inferred to strong.
testNullSafetyMode1(jitPath, 'Strong Mode');
} finally {
tmpDir.deleteSync(recursive: true);
}
}

View file

@ -0,0 +1,38 @@
// Copyright (c) 2020, 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:io";
import "detect_nullsafety_helper.dart";
void main() {
// Create temporary directory.
var tmpDir = Directory.systemTemp.createTempSync();
var tmpDirPath = tmpDir.path;
String sourcePath = "$tmpDirPath/weak.dart";
String dillPath = "$tmpDirPath/weak.dill";
String jitPath = "$tmpDirPath/weak.appjit";
// Generate code for an isolate to run in weak mode.
generateIsolateSource(sourcePath, "2.6");
generateKernel(sourcePath, dillPath);
generateAppJIT(sourcePath, jitPath);
try {
testNullSafetyMode(sourcePath, 'Weak Mode');
// Without the enable experiment option it will be in weak mode.
testNullSafetyMode1(sourcePath, 'Weak Mode');
// Running from Kernel File.
testNullSafetyMode(dillPath, 'Weak Mode');
// Without the enable experiment option it will be inferred to weak.
testNullSafetyMode1(dillPath, 'Weak Mode');
// Running from app JIT File.
testNullSafetyMode(jitPath, 'Weak Mode');
// Without the enable experiment option it will be inferred to weak.
testNullSafetyMode1(jitPath, 'Weak Mode');
} finally {
tmpDir.deleteSync(recursive: true);
}
}

View file

@ -0,0 +1,56 @@
// Copyright (c) 2020, 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:io";
import "package:async_helper/async_minitest.dart";
void generateIsolateSource(String filePath, String version) {
File mainIsolate = new File(filePath);
mainIsolate.writeAsStringSync('''
// @dart=$version
void main() {
try {
int x = null as int;
print("Weak Mode");
} catch (ex) {
print("Strong Mode");
}
}
''');
}
void generateOutput(String sourcePath, String outPath, String type) {
var exec = Platform.resolvedExecutable;
var args = <String>[];
args.add("--snapshot-kind=$type");
args.add("--snapshot=$outPath");
args.add("--enable-experiment=non-nullable");
args.add(sourcePath);
var result = Process.runSync(exec, args);
}
void generateKernel(String sourcePath, String outPath) {
generateOutput(sourcePath, outPath, "kernel");
}
void generateAppJIT(String sourcePath, String outPath) {
generateOutput(sourcePath, outPath, "app-jit");
}
void testNullSafetyMode(String filePath, String expected) {
var exec = Platform.resolvedExecutable;
var args = <String>[];
args.add("--enable-experiment=non-nullable");
args.add(filePath);
var result = Process.runSync(exec, args);
expect(result.stdout.contains('$expected'), true);
}
void testNullSafetyMode1(String filePath, String expected) {
var exec = Platform.resolvedExecutable;
var args = <String>[];
args.add(filePath);
var result = Process.runSync(exec, args);
expect(result.stdout.contains('$expected'), true);
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2020, 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:io";
import "nnbd_spawn_autodetect_helper.dart";
void main() {
// Create temporary directory.
var tmpDir = Directory.systemTemp.createTempSync();
var tmpDirPath = tmpDir.path;
String sourcePath = "$tmpDirPath/strong.dart";
String dillPath = "$tmpDirPath/strong.dill";
String jitPath = "$tmpDirPath/strong.appjit";
// Generate code for an isolate to run in strong mode.
generateIsolateSource(sourcePath, "");
generateKernel(sourcePath, dillPath);
generateAppJIT(sourcePath, jitPath);
try {
// Strong Isolate Spawning another Strong Isolate using spawn.
testNullSafetyMode(sourcePath, 're: strong');
testNullSafetyMode(dillPath, 're: strong');
testNullSafetyMode(jitPath, 're: strong');
} finally {
tmpDir.deleteSync(recursive: true);
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2020, 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:io";
import "nnbd_spawn_autodetect_helper.dart";
void main() {
// Create temporary directory.
var tmpDir = Directory.systemTemp.createTempSync();
var tmpDirPath = tmpDir.path;
String sourcePath = "$tmpDirPath/strong.dart";
String dillPath = "$tmpDirPath/strong.dill";
String jitPath = "$tmpDirPath/strong.appjit";
// Generate code for an isolate to run in strong mode.
generateIsolateSource(sourcePath, "2.6");
generateKernel(sourcePath, dillPath);
generateAppJIT(sourcePath, jitPath);
try {
// Strong Isolate Spawning another Strong Isolate using spawn.
testNullSafetyMode(sourcePath, 're: weak');
testNullSafetyMode(dillPath, 're: weak');
testNullSafetyMode(jitPath, 're: weak');
} finally {
tmpDir.deleteSync(recursive: true);
}
}

View file

@ -0,0 +1,74 @@
// Copyright (c) 2020, 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:io";
import "package:async_helper/async_minitest.dart";
void generateIsolateSource(String filePath, String version) {
File isolateSource = new File(filePath);
isolateSource.writeAsStringSync('''
// @dart=$version
import \'dart:isolate\';
spawnFunc(List args) {
var data = args[0];
var replyTo = args[1];
try {
int x = null as int;
replyTo.send(\'re: weak\');
} catch (ex) {
replyTo.send(\'re: strong\');
}
}
void main() async {
const String debugName = \'spawnedIsolate\';
final exitPort = ReceivePort();
final port = new ReceivePort();
port.listen((msg) {
print(msg);
port.close();
});
final isolate = await Isolate.spawn(
spawnFunc,
[\'re: hi\', port.sendPort],
paused: false,
debugName: debugName,
onExit: exitPort.sendPort);
// Explicitly await spawned isolate exit to enforce main isolate not
// completing (and the stand-alone runtime exiting) before the spawned
// isolate is done.
await exitPort.first;
}
''');
}
void generateOutput(String sourcePath, String outPath, String type) {
var exec = Platform.resolvedExecutable;
var args = <String>[];
args.add("--snapshot-kind=$type");
args.add("--snapshot=$outPath");
args.add("--enable-experiment=non-nullable");
args.add(sourcePath);
var result = Process.runSync(exec, args);
}
void generateKernel(String sourcePath, String outPath) {
generateOutput(sourcePath, outPath, "kernel");
}
void generateAppJIT(String sourcePath, String outPath) {
generateOutput(sourcePath, outPath, "app-jit");
}
void testNullSafetyMode(String filePath, String expected) {
var exec = Platform.resolvedExecutable;
var args = <String>[];
args.add("--enable-experiment=non-nullable");
args.add(filePath);
var result = Process.runSync(exec, args);
expect(result.stdout.contains('$expected'), true);
}

View file

@ -1,69 +0,0 @@
// Copyright (c) 2020, 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:io";
import "package:async_helper/async_minitest.dart";
void testNullSafetyMode(String filePath, String version, String expected) {
File mainIsolate = new File(filePath);
mainIsolate.writeAsStringSync('''
// $version
import \'dart:isolate\';
spawnFunc(List args) {
var data = args[0];
var replyTo = args[1];
try {
int x = null as int;
replyTo.send(\'re: weak\');
} catch (ex) {
replyTo.send(\'re: strong\');
}
}
void main() async {
const String debugName = \'spawnedIsolate\';
final exitPort = ReceivePort();
final port = new ReceivePort();
port.listen((msg) {
print(msg);
port.close();
});
final isolate = await Isolate.spawn(
spawnFunc,
[\'re: hi\', port.sendPort],
paused: false,
debugName: debugName,
onExit: exitPort.sendPort);
// Explicitly await spawned isolate exit to enforce main isolate not
// completing (and the stand-alone runtime exiting) before the spawned
// isolate is done.
await exitPort.first;
}
''');
var exec = Platform.resolvedExecutable;
var args = <String>[];
args.add("--enable-experiment=non-nullable");
args.add(mainIsolate.path);
var result = Process.runSync(exec, args);
expect(result.stdout.contains('$expected'), true);
}
void main() {
// Create temporary directory.
var tmpDir = Directory.systemTemp.createTempSync();
var tmpDirPath = tmpDir.path;
try {
// Strong Isolate Spawning another Strong Isolate using spawn.
testNullSafetyMode("$tmpDirPath/strong.dart", '', 're: strong');
// Weak Isolate Spawning a Weak Isolate using spawn.
testNullSafetyMode("$tmpDirPath/weak.dart", '@dart=2.6', 're: weak');
} finally {
tmpDir.deleteSync(recursive: true);
}
}

View file

@ -0,0 +1,28 @@
// Copyright (c) 2020, 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:io";
import "nnbd_spawnuri_autodetect_helper.dart";
void main() {
// Create temporary directory.
var tmpDir = Directory.systemTemp.createTempSync();
var tmpDirPath = tmpDir.path;
String sourcePath = "$tmpDirPath/strong_isolate.dart";
// Generate code for an isolate to run in strong mode.
generateIsolateSource(sourcePath, "");
try {
// Strong Isolate Spawning another Strong Isolate using spawnUri.
testNullSafetyMode(
"$tmpDirPath/strong_strong.dart", "", sourcePath, 're: strong');
// Weak Isolate Spawning a Strong Isolate using spawnUri.
testNullSafetyMode(
"$tmpDirPath/weak_strong.dart", "2.6", sourcePath, 're: strong');
} finally {
tmpDir.deleteSync(recursive: true);
}
}

View file

@ -0,0 +1,28 @@
// Copyright (c) 2020, 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:io";
import "nnbd_spawnuri_autodetect_helper.dart";
void main() {
// Create temporary directory.
var tmpDir = Directory.systemTemp.createTempSync();
var tmpDirPath = tmpDir.path;
String sourcePath = "$tmpDirPath/weak_isolate.dart";
// Generate code for an isolate to run in strong mode.
generateIsolateSource(sourcePath, "2.6");
try {
// Strong Isolate Spawning another weak Isolate using spawnUri.
testNullSafetyMode(
"$tmpDirPath/strong_weak.dart", "", sourcePath, 're: weak');
// Weak Isolate Spawning another Weak Isolate using spawnUri.
testNullSafetyMode(
"$tmpDirPath/weak_weak.dart", "2.6", sourcePath, 're: weak');
} finally {
tmpDir.deleteSync(recursive: true);
}
}

View file

@ -0,0 +1,30 @@
// Copyright (c) 2020, 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:io";
import "nnbd_spawnuri_autodetect_helper.dart";
void main() {
// Create temporary directory.
var tmpDir = Directory.systemTemp.createTempSync();
var tmpDirPath = tmpDir.path;
String sourcePath = "$tmpDirPath/strong_isolate.dart";
String outPath = "$tmpDirPath/strong_isolate.dill";
// Generate code for an isolate to run in strong mode.
generateIsolateSource(sourcePath, "");
generateKernel(sourcePath, outPath);
try {
// Strong Isolate Spawning another Strong Isolate using spawnUri.
testNullSafetyMode(
"$tmpDirPath/strong_strong.dart", "", outPath, 're: strong');
// Weak Isolate Spawning a Strong Isolate using spawnUri.
testNullSafetyMode(
"$tmpDirPath/weak_strong.dart", "2.6", outPath, 're: strong');
} finally {
tmpDir.deleteSync(recursive: true);
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2020, 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:io";
import "nnbd_spawnuri_autodetect_helper.dart";
void main() {
// Create temporary directory.
var tmpDir = Directory.systemTemp.createTempSync();
var tmpDirPath = tmpDir.path;
String sourcePath = "$tmpDirPath/weak_isolate.dart";
String outPath = "$tmpDirPath/weak_isolate.dill";
// Generate code for an isolate to run in strong mode.
generateIsolateSource(sourcePath, "2.6");
generateKernel(sourcePath, outPath);
try {
// Strong Isolate Spawning another weak Isolate using spawnUri.
testNullSafetyMode("$tmpDirPath/strong_weak.dart", "", outPath, 're: weak');
// Weak Isolate Spawning another Weak Isolate using spawnUri.
testNullSafetyMode(
"$tmpDirPath/weak_weak.dart", "2.6", outPath, 're: weak');
} finally {
tmpDir.deleteSync(recursive: true);
}
}

View file

@ -0,0 +1,81 @@
// Copyright (c) 2020, 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:io";
import "package:async_helper/async_minitest.dart";
void generateIsolateSource(String filePath, String version) {
File isolateSource = new File("$filePath");
isolateSource.writeAsStringSync('''
// @dart=$version
library SpawnUriIsolate;
main(List<String> args, replyTo) {
var data = args[0];
try {
int x = null as int;
replyTo.send(\'re: weak\');
} catch (ex) {
replyTo.send(\'re: strong\');
}
}
''');
}
void generateOutput(String sourcePath, String outPath, String type) {
var exec = Platform.resolvedExecutable;
var args = <String>[];
args.add("--snapshot-kind=$type");
args.add("--snapshot=$outPath");
args.add("--enable-experiment=non-nullable");
args.add(sourcePath);
var result = Process.runSync(exec, args);
}
void generateKernel(String sourcePath, String outPath) {
generateOutput(sourcePath, outPath, "kernel");
}
void generateAppJIT(String sourcePath, String outPath) {
generateOutput(sourcePath, outPath, "app-jit");
}
void testNullSafetyMode(
String filePath, String version, String uri, String expected) {
File mainIsolate = new File(filePath);
mainIsolate.writeAsStringSync('''
// @dart=$version
library spawn_tests;
import \'dart:isolate\';
void main() async {
const String debugName = \'spawnedIsolate\';
final exitPort = ReceivePort();
final port = new ReceivePort();
port.listen((msg) {
print(msg);
port.close();
});
final isolate = await Isolate.spawnUri(
Uri.parse(\'$uri\'),
[\'re: hi\'],
port.sendPort,
paused: false,
debugName: debugName,
onExit: exitPort.sendPort);
// Explicitly await spawned isolate exit to enforce main isolate not
// completing (and the stand-alone runtime exiting) before the spawned
// isolate is done.
await exitPort.first;
}
''');
var exec = Platform.resolvedExecutable;
var args = <String>[];
args.add("--enable-experiment=non-nullable");
args.add(mainIsolate.path);
var result = Process.runSync(exec, args);
expect(result.stdout.contains('$expected'), true);
}

View file

@ -1,101 +0,0 @@
// Copyright (c) 2020, 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:io";
import "package:async_helper/async_minitest.dart";
void testNullSafetyMode(String filePath, String uri, String expected) {
File mainIsolate = new File(filePath);
mainIsolate.writeAsStringSync('''
library spawn_tests;
import \'dart:isolate\';
void main() async {
const String debugName = \'spawnedIsolate\';
final exitPort = ReceivePort();
final port = new ReceivePort();
port.listen((msg) {
print(msg);
port.close();
});
final isolate = await Isolate.spawnUri(
Uri.parse(\'$uri\'),
[\'re: hi\'],
port.sendPort,
paused: false,
debugName: debugName,
onExit: exitPort.sendPort);
// Explicitly await spawned isolate exit to enforce main isolate not
// completing (and the stand-alone runtime exiting) before the spawned
// isolate is done.
await exitPort.first;
}
''');
var exec = Platform.resolvedExecutable;
var args = <String>[];
args.add("--enable-experiment=non-nullable");
args.add(mainIsolate.path);
var result = Process.runSync(exec, args);
expect(result.stdout.contains('$expected'), true);
}
void main() {
// Create temporary directory.
var tmpDir = Directory.systemTemp.createTempSync();
var tmpDirPath = tmpDir.path;
// Generate code for an isolate to run in strong mode.
File strongIsolate = new File("$tmpDirPath/strong_isolate.dart");
strongIsolate.writeAsStringSync('''
library SpawnUriStrongIsolate;
main(List<String> args, replyTo) {
var data = args[0];
try {
int x = null as int;
replyTo.send(\'re: weak\');
} catch (ex) {
replyTo.send(\'re: strong\');
}
}
''');
// Generate code for an isolate to run in weak mode.
File weakIsolate = new File("$tmpDirPath/weak_isolate.dart");
weakIsolate.writeAsStringSync('''
// @dart=2.7
library SpawnUriStrongIsolate;
main(List<String> args, replyTo) {
var data = args[0];
try {
int x = null as int;
replyTo.send(\'re: weak\');
} catch (ex) {
replyTo.send(\'re: strong\');
}
}
''');
try {
// Strong Isolate Spawning another Strong Isolate using spawnUri.
testNullSafetyMode(
"$tmpDirPath/strong_strong.dart", strongIsolate.path, 're: strong');
// Strong Isolate Spawning a Weak Isolate using spawnUri.
testNullSafetyMode(
"$tmpDirPath/strong_weak.dart", weakIsolate.path, 're: weak');
// Weak Isolate Spawning a Strong Isolate using spawnUri.
testNullSafetyMode(
"$tmpDirPath/weak_strong.dart", strongIsolate.path, 're: strong');
// Weak Isolate Spawning a Weak Isolate using spawnUri.
testNullSafetyMode(
"$tmpDirPath/weak_weak.dart", weakIsolate.path, 're: weak');
} finally {
tmpDir.deleteSync(recursive: true);
}
}

View file

@ -79,6 +79,8 @@ isolate/count_test: Skip # Isolate.spawnUri
isolate/cross_isolate_message_test: Skip # Isolate.spawnUri
isolate/deferred_in_isolate2_test: Skip # Isolate.spawnUri
isolate/deferred_in_isolate_test: Skip # Isolate.spawnUri
isolate/detect_nullsafety_1_test: Skip # Tests Source, Kernel, appJIT modes
isolate/detect_nullsafety_2_test: Skip # Tests Source, Kernel, appJIT modes
isolate/error_at_spawnuri_test: Skip # Isolate.spawnUri
isolate/error_exit_at_spawnuri_test: Skip # Isolate.spawnUri
isolate/exit_at_spawnuri_test: Skip # Isolate.spawnUri
@ -95,8 +97,12 @@ isolate/message_test: Skip # Isolate.spawnUri
isolate/mint_maker_test: Skip # Isolate.spawnUri
isolate/nested_spawn2_test: Skip # Isolate.spawnUri
isolate/nested_spawn_test: Skip # Isolate.spawnUri
isolate/nnbd_spawn_autodetect_test: Skip # Auto detect not for precompiled.
isolate/nnbd_spawnuri_autodetect_test: Skip # Auto detect not for precompiled.
isolate/nnbd_spawn_autodetect_1_test: Skip # Tests Source, Kernel, appJIT modes
isolate/nnbd_spawn_autodetect_2_test: Skip # Tests Source, Kernel, appJIT modes
isolate/nnbd_spawnuri_autodetect_1_test: Skip # Uses Isolate.spawnUri
isolate/nnbd_spawnuri_autodetect_2_test: Skip # Uses Isolate.spawnUri
isolate/nnbd_spawnuri_autodetect_3_test: Skip # Uses Isolate.spawnUri
isolate/nnbd_spawnuri_autodetect_4_test: Skip # Uses Isolate.spawnUri
isolate/no_package_test: Skip # Isolate.spawnUri
isolate/package_config_test: Skip # Isolate.spawnUri
isolate/raw_port_test: Skip # Isolate.spawnUri