diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc index 1e08dad0b5e..01c02efcf64 100644 --- a/runtime/lib/isolate.cc +++ b/runtime/lib/isolate.cc @@ -181,8 +181,13 @@ static bool CreateIsolate(Isolate* parent_isolate, if (child_isolate == NULL) { return false; } + // TODO(iposva): Evaluate whether it's ok to override the embedder's setup. + // Currently the strict_compilation flag is ignored if it's false and + // checked-mode was enabled using a command-line flag. The command-line flag + // overrides the user code's request. + child_isolate->set_strict_compilation(state->checked_mode()); if (!state->is_spawn_uri()) { - // For isolates spawned using the spawnFunction semantics we set + // For isolates spawned using the spawn semantics we set // the origin_id to the origin_id of the parent isolate. child_isolate->set_origin_id(parent_isolate->origin_id()); } @@ -229,10 +234,12 @@ DEFINE_NATIVE_ENTRY(Isolate_spawnFunction, 4) { #endif // Get the parent function so that we get the right function name. func = func.parent_function(); + bool checkedFlag = isolate->strict_compilation(); Spawn(isolate, new IsolateSpawnState(port.Id(), func, message, - paused.value())); + paused.value(), + checkedFlag)); return Object::null(); } } @@ -243,13 +250,14 @@ DEFINE_NATIVE_ENTRY(Isolate_spawnFunction, 4) { } -DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 6) { +DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 7) { GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0)); GET_NON_NULL_NATIVE_ARGUMENT(String, uri, arguments->NativeArgAt(1)); GET_NON_NULL_NATIVE_ARGUMENT(Instance, args, arguments->NativeArgAt(2)); GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(3)); GET_NON_NULL_NATIVE_ARGUMENT(Bool, paused, arguments->NativeArgAt(4)); - GET_NATIVE_ARGUMENT(String, package_root, arguments->NativeArgAt(5)); + GET_NATIVE_ARGUMENT(Bool, checked, arguments->NativeArgAt(5)); + GET_NATIVE_ARGUMENT(String, package_root, arguments->NativeArgAt(6)); // Canonicalize the uri with respect to the current isolate. char* error = NULL; @@ -270,12 +278,20 @@ DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 6) { utf8_package_root[len] = '\0'; } + bool checkedFlag; + if (checked.IsNull()) { + checkedFlag = isolate->strict_compilation(); + } else { + checkedFlag = checked.value(); + } + Spawn(isolate, new IsolateSpawnState(port.Id(), canonical_uri, utf8_package_root, args, message, - paused.value())); + paused.value(), + checkedFlag)); return Object::null(); } diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart index 100d951a647..1fd87bfb0c1 100644 --- a/runtime/lib/isolate_patch.dart +++ b/runtime/lib/isolate_patch.dart @@ -303,8 +303,7 @@ patch class Isolate { /* patch */ static Future spawnUri( Uri uri, List args, var message, - { bool paused: false, Uri packageRoot }) { - // `paused` isn't handled yet. + { bool paused: false, bool checked, Uri packageRoot }) { RawReceivePort readyPort; try { // The VM will invoke [_startIsolate] and not `main`. @@ -312,7 +311,7 @@ patch class Isolate { var packageRootString = (packageRoot == null) ? null : packageRoot.toString(); _spawnUri(readyPort.sendPort, uri.toString(), args, message, - paused, packageRootString); + paused, checked, packageRootString); Completer completer = new Completer.sync(); readyPort.handler = (readyMessage) { readyPort.close(); @@ -354,7 +353,7 @@ patch class Isolate { static void _spawnUri(SendPort readyPort, String uri, List args, var message, - bool paused, String packageRoot) + bool paused, bool checked, String packageRoot) native "Isolate_spawnUri"; static void _sendOOB(port, msg) native "Isolate_sendOOB"; diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h index 270b76ba604..d5ae74c2b06 100644 --- a/runtime/vm/bootstrap_natives.h +++ b/runtime/vm/bootstrap_natives.h @@ -293,7 +293,7 @@ namespace dart { V(Int32x4_setFlagW, 2) \ V(Int32x4_select, 3) \ V(Isolate_spawnFunction, 4) \ - V(Isolate_spawnUri, 6) \ + V(Isolate_spawnUri, 7) \ V(Isolate_getPortAndCapabilitiesOfCurrentIsolate, 0) \ V(Isolate_sendOOB, 2) \ V(Mirrors_evalInLibraryWithPrivateKey, 2) \ diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc index ec9fbd3b100..e526d446cd9 100644 --- a/runtime/vm/isolate.cc +++ b/runtime/vm/isolate.cc @@ -1799,7 +1799,8 @@ static RawInstance* DeserializeObject(Isolate* isolate, IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port, const Function& func, const Instance& message, - bool paused) + bool paused, + bool checkedFlag) : isolate_(NULL), parent_port_(parent_port), script_url_(NULL), @@ -1811,7 +1812,8 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port, serialized_args_len_(0), serialized_message_(NULL), serialized_message_len_(0), - paused_(paused) { + paused_(paused), + checked_(checkedFlag) { script_url_ = NULL; const Class& cls = Class::Handle(func.Owner()); const Library& lib = Library::Handle(cls.library()); @@ -1837,7 +1839,8 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port, const char* package_root, const Instance& args, const Instance& message, - bool paused) + bool paused, + bool checkedFlag) : isolate_(NULL), parent_port_(parent_port), package_root_(NULL), @@ -1848,7 +1851,8 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port, serialized_args_len_(0), serialized_message_(NULL), serialized_message_len_(0), - paused_(paused) { + paused_(paused), + checked_(checkedFlag) { script_url_ = strdup(script_url); if (package_root != NULL) { package_root_ = strdup(package_root); diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h index 57b23e9e707..a74bc944ba8 100644 --- a/runtime/vm/isolate.h +++ b/runtime/vm/isolate.h @@ -926,13 +926,15 @@ class IsolateSpawnState { IsolateSpawnState(Dart_Port parent_port, const Function& func, const Instance& message, - bool paused); + bool paused, + bool checked); IsolateSpawnState(Dart_Port parent_port, const char* script_url, const char* package_root, const Instance& args, const Instance& message, - bool paused); + bool paused, + bool checked); ~IsolateSpawnState(); Isolate* isolate() const { return isolate_; } @@ -946,6 +948,7 @@ class IsolateSpawnState { char* function_name() const { return function_name_; } bool is_spawn_uri() const { return library_url_ == NULL; } bool paused() const { return paused_; } + bool checked_mode() const { return checked_; } RawObject* ResolveFunction(); RawInstance* BuildArgs(Zone* zone); @@ -965,6 +968,7 @@ class IsolateSpawnState { uint8_t* serialized_message_; intptr_t serialized_message_len_; bool paused_; + bool checked_; }; } // namespace dart diff --git a/sdk/lib/_internal/compiler/js_lib/isolate_patch.dart b/sdk/lib/_internal/compiler/js_lib/isolate_patch.dart index b01318c713d..49153743992 100644 --- a/sdk/lib/_internal/compiler/js_lib/isolate_patch.dart +++ b/sdk/lib/_internal/compiler/js_lib/isolate_patch.dart @@ -37,6 +37,7 @@ class Isolate { @patch static Future spawnUri( Uri uri, List args, var message, { bool paused: false, + bool checked, Uri packageRoot }) { if (packageRoot != null) throw new UnimplementedError("packageRoot"); try { diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart index 8c46d6047e2..8372eafbc16 100644 --- a/sdk/lib/isolate/isolate.dart +++ b/sdk/lib/isolate/isolate.dart @@ -148,8 +148,6 @@ class Isolate { * before it starts running. * To resume the isolate, call `isolate.resume(isolate.pauseCapability)`. * - * WARNING: The `pause` parameter is not implemented on all platforms yet. - * * Returns a future that will complete with an [Isolate] instance if the * spawning succeeded. It will complete with an error otherwise. */ @@ -172,6 +170,26 @@ class Isolate { * When present, the parameter `args` is set to the provided [args] list. * When present, the parameter `message` is set to the initial [message]. * + * If the [paused] parameter is set to `true`, + * the isolate will start up in a paused state, + * as if by an initial call of `isolate.pause(isolate.pauseCapability)`. + * This allows setting up error or exit listeners on the isolate + * before it starts running. + * To resume the isolate, call `isolate.resume(isolate.pauseCapability)`. + * + * If the [checked] parameter is set to `true` or `false`, + * the new isolate will run code in checked mode, + * respectively in production mode, if possible. + * If the parameter is omitted, the new isolate will inherit the + * value from the current isolate. + * + * It may not always be possible to honor the `checked` parameter. + * If the isolate code was pre-compiled, it may not be possible to change + * the checked mode setting dynamically. + * In that case, the `checked` parameter is ignored. + * + * WARNING: The [checked] parameter is not implemented on all platforms yet. + * * If the [packageRoot] parameter is provided, it is used to find the location * of packages imports in the spawned isolate. * The `packageRoot` URI must be a "file" or "http"/"https" URI that specifies @@ -187,15 +205,6 @@ class Isolate { * WARNING: The [packageRoot] parameter is not implemented on all * platforms yet. * - * If the [paused] parameter is set to `true`, - * the isolate will start up in a paused state, - * as if by an initial call of `isolate.pause(isolate.pauseCapability)`. - * This allows setting up error or exit listeners on the isolate - * before it starts running. - * To resume the isolate, call `isolate.resume(isolate.pauseCapability)`. - * - * WARNING: The `pause` parameter is not implemented on all platforms yet. - * * Returns a future that will complete with an [Isolate] instance if the * spawning succeeded. It will complete with an error otherwise. */ @@ -204,6 +213,7 @@ class Isolate { List args, var message, {bool paused: false, + bool checked, Uri packageRoot}); /** diff --git a/tests/isolate/checked_test.dart b/tests/isolate/checked_test.dart new file mode 100644 index 00000000000..87f6a036ddc --- /dev/null +++ b/tests/isolate/checked_test.dart @@ -0,0 +1,48 @@ +// Copyright (c) 2014, 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:isolate"; +import "dart:async"; +import "package:expect/expect.dart"; +import "package:async_helper/async_helper.dart"; + +void main([args, message]) { + if (message != null) return isolateMain(message); + + bool isChecked = false; + assert((isChecked = true)); + if (isChecked) return; // Skip this test in checked mode. + + var responses = {}; + var port = new RawReceivePort(); + port.handler = (pair) { + responses[pair[0]] = pair[1]; + if (responses.length == 3) { + port.close(); + Expect.isTrue(responses[true], "true @ $isChecked"); + Expect.isTrue(responses[false], "false @ $isChecked"); + Expect.isTrue(responses[null], "null @ $isChecked"); + } + }; + test(checked) { + Isolate.spawnUri(Uri.parse("checked_test.dart"), [], + [checked, isChecked, port.sendPort], + checked: checked); + } + test(true); + test(false); + test(null); +} + + +void isolateMain(args) { + var checkedFlag = args[0]; + var parentIsChecked = args[1]; + var responsePort = args[2]; + bool isChecked = false; + assert((isChecked = true)); + bool expected = checkedFlag; + if (checkedFlag == null) expected = parentIsChecked; + responsePort.send([checkedFlag, expected == isChecked]); +} diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status index c02d25e30f8..5c2a946f0d4 100644 --- a/tests/isolate/isolate.status +++ b/tests/isolate/isolate.status @@ -6,6 +6,9 @@ browser/*: SkipByDesign # Browser specific tests isolate_stress_test: Fail # Issue 12588: This should be able to pass when we have wrapper-less tests. +[ $runtime != vm ] +checked_test: Skip # Unsupported. + [ $runtime == vm && $arch == mips && $mode == debug ] mandel_isolate_test: Skip # Uses 600 MB Ram on our 1 GB test device.