Reapply "[mirrors] Add IsolateMirror.loadUri."

- Forward only kImportTag requests to DFE. This restores the current handling of a kScriptTag request when loading the kernel isolate in the simulators.
 - Mark dynamic_load_test as failing in the reload stress tests (reload fails to preserve library identity).

Change-Id: Ibe6f0a3505b99736a38d566abf3b2151505d7a7e
Reviewed-on: https://dart-review.googlesource.com/56706
Reviewed-by: Siva Annamalai <asiva@google.com>
This commit is contained in:
Ryan Macnak 2018-05-29 22:01:01 +00:00
parent a40993a6af
commit c30af41b96
12 changed files with 249 additions and 6 deletions

View file

@ -583,6 +583,10 @@ Still need entries for all changes to dart:js since 1.x
* Renamed `E`, `LN10`, `LN`, `LOG2E`, `LOG10E`, `PI`, `SQRT1_2` and `SQRT2`
to `e`, `ln10`, `ln`, `log2e`, `log10e`, `pi`, `sqrt1_2` and `sqrt2`.
* `dart.mirrors`
* Added `IsolateMirror.loadUri`, which allows dynamically loading additional
code.
<!--
Still need entries for all changes to dart:svg since 1.x
-->

View file

@ -7,6 +7,7 @@
#include "bin/builtin.h"
#include "bin/dartutils.h"
#include "bin/dfe.h"
#include "bin/error_exit.h"
#include "bin/extensions.h"
#include "bin/file.h"
#include "bin/gzip.h"
@ -660,7 +661,6 @@ Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag,
if (Dart_IsError(result)) {
return result;
}
Dart_Isolate current = Dart_CurrentIsolate();
if (tag == Dart_kKernelTag) {
uint8_t* kernel_buffer = NULL;
intptr_t kernel_buffer_size = 0;
@ -687,7 +687,6 @@ Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag,
return Extensions::LoadExtension("/", absolute_path, library);
}
ASSERT(Dart_IsKernelIsolate(current) || !dfe.UseDartFrontend());
if (tag != Dart_kScriptTag) {
// Special case for handling dart: imports and parts.
// Grab the library's url.
@ -766,8 +765,25 @@ Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag,
loader->SendImportExtensionRequest(url, Dart_LibraryUrl(library));
} else {
if (dfe.CanUseDartFrontend() && dfe.UseDartFrontend() &&
!Dart_IsKernelIsolate(current)) {
FATAL("Loader should not be called to compile scripts to kernel.");
(tag == Dart_kImportTag)) {
// E.g., IsolateMirror.loadUri.
char* error = NULL;
int exit_code = 0;
uint8_t* kernel_buffer = NULL;
intptr_t kernel_buffer_size = -1;
dfe.CompileAndReadScript(url_string, &kernel_buffer, &kernel_buffer_size,
&error, &exit_code, true /* strong */, NULL);
if (exit_code == 0) {
return Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size);
} else if (exit_code == kCompilationErrorExitCode) {
Dart_Handle result = Dart_NewCompilationError(error);
free(error);
return result;
} else {
Dart_Handle result = Dart_NewApiError(error);
free(error);
return result;
}
} else {
loader->SendRequest(
tag, url,

View file

@ -351,6 +351,7 @@ DART_EXPORT Dart_Handle Dart_ErrorGetStackTrace(Dart_Handle handle);
* \param error the error message.
*/
DART_EXPORT Dart_Handle Dart_NewApiError(const char* error);
DART_EXPORT Dart_Handle Dart_NewCompilationError(const char* error);
/**
* Produces a new unhandled exception error handle.

View file

@ -9,6 +9,7 @@
#include "vm/class_finalizer.h"
#include "vm/compiler/frontend/kernel_to_il.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/dart_api_impl.h"
#include "vm/dart_entry.h"
#include "vm/exceptions.h"
#include "vm/flags.h"
@ -759,6 +760,95 @@ DEFINE_NATIVE_ENTRY(MirrorSystem_isolate, 0) {
return CreateIsolateMirror();
}
static void ThrowLanguageError(const char* message) {
const Error& error =
Error::Handle(LanguageError::New(String::Handle(String::New(message))));
Exceptions::PropagateError(error);
}
DEFINE_NATIVE_ENTRY(IsolateMirror_loadUri, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(String, uri, arguments->NativeArgAt(0));
Dart_LibraryTagHandler handler = isolate->library_tag_handler();
if (handler == NULL) {
ThrowLanguageError("no library handler registered");
}
// Canonicalize library URI.
String& canonical_uri = String::Handle(zone);
if (uri.StartsWith(Symbols::DartScheme())) {
canonical_uri = uri.raw();
} else {
isolate->BlockClassFinalization();
Object& result = Object::Handle(zone);
{
TransitionVMToNative transition(thread);
Api::Scope api_scope(thread);
Dart_Handle retval = handler(
Dart_kCanonicalizeUrl,
Api::NewHandle(thread, isolate->object_store()->root_library()),
Api::NewHandle(thread, uri.raw()));
result = Api::UnwrapHandle(retval);
}
isolate->UnblockClassFinalization();
if (result.IsError()) {
if (result.IsLanguageError()) {
Exceptions::ThrowCompileTimeError(LanguageError::Cast(result));
}
Exceptions::PropagateError(Error::Cast(result));
} else if (!result.IsString()) {
ThrowLanguageError("library handler failed URI canonicalization");
}
canonical_uri ^= result.raw();
}
// Create a new library if it does not exist yet.
Library& library =
Library::Handle(zone, Library::LookupLibrary(thread, canonical_uri));
if (library.IsNull()) {
library = Library::New(canonical_uri);
library.Register(thread);
}
// Ensure loading started.
if (library.LoadNotStarted()) {
library.SetLoadRequested();
isolate->BlockClassFinalization();
Object& result = Object::Handle(zone);
{
TransitionVMToNative transition(thread);
Api::Scope api_scope(thread);
Dart_Handle retval = handler(
Dart_kImportTag,
Api::NewHandle(thread, isolate->object_store()->root_library()),
Api::NewHandle(thread, canonical_uri.raw()));
result = Api::UnwrapHandle(retval);
}
isolate->UnblockClassFinalization();
if (result.IsError()) {
if (result.IsLanguageError()) {
Exceptions::ThrowCompileTimeError(LanguageError::Cast(result));
}
Exceptions::PropagateError(Error::Cast(result));
}
}
if (!library.Loaded()) {
// This code assumes a synchronous tag handler (which dart::bin and tonic
// provide). Strictly though we should complete a future in response to
// Dart_FinalizeLoading.
UNIMPLEMENTED();
}
if (!ClassFinalizer::ProcessPendingClasses()) {
Exceptions::PropagateError(Error::Handle(thread->sticky_error()));
}
return CreateLibraryMirror(thread, library);
}
DEFINE_NATIVE_ENTRY(Mirrors_makeLocalClassMirror, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
PROPAGATE_IF_MALFORMED(type);

View file

@ -125,6 +125,17 @@ class _LocalIsolateMirror extends _LocalMirror implements IsolateMirror {
bool get isCurrent => true;
String toString() => "IsolateMirror on '$debugName'";
Future<LibraryMirror> loadUri(Uri uri) async {
var result = _loadUri(uri.toString());
if (result == null) {
// Censored library.
throw new Exception("Cannot load $uri");
}
return result;
}
static LibraryMirror _loadUri(String uri) native "IsolateMirror_loadUri";
}
class _SyntheticAccessor implements MethodMirror {

View file

@ -364,6 +364,7 @@ namespace dart {
V(MirrorReference_equals, 2) \
V(MirrorSystem_libraries, 0) \
V(MirrorSystem_isolate, 0) \
V(IsolateMirror_loadUri, 1) \
V(InstanceMirror_invoke, 5) \
V(InstanceMirror_invokeGetter, 3) \
V(InstanceMirror_invokeSetter, 4) \

View file

@ -791,8 +791,6 @@ DART_EXPORT Dart_Handle Dart_ErrorGetStackTrace(Dart_Handle handle) {
}
}
// TODO(turnidge): This clones Api::NewError. I need to use va_copy to
// fix this but not sure if it available on all of our builds.
DART_EXPORT Dart_Handle Dart_NewApiError(const char* error) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
@ -801,6 +799,14 @@ DART_EXPORT Dart_Handle Dart_NewApiError(const char* error) {
return Api::NewHandle(T, ApiError::New(message));
}
DART_EXPORT Dart_Handle Dart_NewCompilationError(const char* error) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
const String& message = String::Handle(Z, String::New(error));
return Api::NewHandle(T, LanguageError::New(message));
}
DART_EXPORT Dart_Handle Dart_NewUnhandledExceptionError(Dart_Handle exception) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);

View file

@ -220,6 +220,23 @@ abstract class IsolateMirror implements Mirror {
* reflected by [other].
*/
bool operator ==(other);
/**
* Loads the library at the given uri into this isolate.
*
* WARNING: You are strongly encouraged to use Isolate.spawnUri instead when
* possible. IsolateMirror.loadUri should only be used when synchronous
* communication or shared state with dynamically loaded code is needed.
*
* If a library with the same canonicalized uri has already been loaded,
* the existing library will be returned. (The isolate will not load a new
* copy of the library.)
*
* This behavior is similar to the behavior of an import statement that
* appears in the root library, except that the import scope of the root
* library is not changed.
*/
Future<LibraryMirror> loadUri(Uri uri);
}
/**

View file

@ -115,6 +115,7 @@ isolate/deferred_in_isolate2_test: Skip # Issue 16898. Deferred loading does not
[ $hot_reload ]
async/stream_periodic4_test: Pass, RuntimeError # Issue 30904
async/timer_regress22626_test: Pass, RuntimeError # Timing dependent.
mirrors/dynamic_load_test: RuntimeError # Issue 26869 - Reload fails to preserve library identity
[ $jscl ]
isolate/spawn_uri_multi_test/none: RuntimeError # Issue 13544

View file

@ -0,0 +1,6 @@
// Copyright (c) 2018, 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.
// A top-level parse error:
import import import import

View file

@ -0,0 +1,9 @@
// Copyright (c) 2018, 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.
library dynamic_load_success;
int _counter = 0;
advanceCounter() => ++_counter;

View file

@ -0,0 +1,81 @@
// Copyright (c) 2018, 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:async';
import 'dart:mirrors';
import 'package:expect/expect.dart';
main() async {
IsolateMirror isolate = currentMirrorSystem().isolate;
print(isolate);
LibraryMirror success =
await isolate.loadUri(Uri.parse("dynamic_load_success.dart"));
print(success);
InstanceMirror result = success.invoke(#advanceCounter, []);
print(result);
Expect.equals(1, result.reflectee);
result = success.invoke(#advanceCounter, []);
print(result);
Expect.equals(2, result.reflectee);
LibraryMirror success2 =
await isolate.loadUri(Uri.parse("dynamic_load_success.dart"));
print(success2);
Expect.equals(success, success2);
result = success2.invoke(#advanceCounter, []);
print(result);
Expect.equals(3, result.reflectee); // Same library, same state.
LibraryMirror math = await isolate.loadUri(Uri.parse("dart:math"));
result = math.invoke(#max, [3, 4]);
print(result);
Expect.equals(4, result.reflectee);
Future<LibraryMirror> bad_load = isolate.loadUri(Uri.parse("DOES_NOT_EXIST"));
var error;
try {
await bad_load;
} catch (e) {
error = e;
}
print(error);
Expect.isTrue(error.toString().contains("Cannot open file") ||
error.toString().contains("No such file or directory"));
Expect.isTrue(error.toString().contains("DOES_NOT_EXIST"));
Future<LibraryMirror> bad_load2 = isolate.loadUri(Uri.parse("dart:_builtin"));
var error2;
try {
await bad_load2;
} catch (e) {
error2 = e;
}
print(error2);
Expect.isTrue(error2.toString().contains("Cannot load"));
Expect.isTrue(error2.toString().contains("dart:_builtin"));
// Check error is not sticky.
LibraryMirror success3 =
await isolate.loadUri(Uri.parse("dynamic_load_success.dart"));
print(success3);
Expect.equals(success, success3);
result = success3.invoke(#advanceCounter, []);
print(result);
Expect.equals(4, result.reflectee); // Same library, same state.
Future<LibraryMirror> bad_load3 =
isolate.loadUri(Uri.parse("dynamic_load_error.dart"));
var error3;
try {
await bad_load3;
} catch (e) {
error3 = e;
}
print(error3);
Expect.isTrue(error3.toString().contains("library url expected") ||
error3.toString().contains("Error: Expected a String"));
Expect.isTrue(error3.toString().contains("dynamic_load_error.dart"));
}