mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 14:49:43 +00:00
Reload native extensions when starting from a snapshot.
Fixes #21180 Fixes #27574 R=johnmccutchan@google.com Review URL: https://codereview.chromium.org/2475523002 .
This commit is contained in:
parent
4b2751a80e
commit
987165f022
|
@ -233,6 +233,16 @@ const char* DartUtils::RemoveScheme(const char* url) {
|
|||
}
|
||||
|
||||
|
||||
char* DartUtils::DirName(const char* url) {
|
||||
const char* slash = strrchr(url, File::PathSeparator()[0]);
|
||||
if (slash == NULL) {
|
||||
return strdup(url);
|
||||
} else {
|
||||
return strndup(url, slash - url + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void* DartUtils::OpenFile(const char* name, bool write) {
|
||||
File* file = File::Open(name, write ? File::kWriteTruncate : File::kRead);
|
||||
return reinterpret_cast<void*>(file);
|
||||
|
|
|
@ -126,6 +126,7 @@ class DartUtils {
|
|||
static bool IsDartBuiltinLibURL(const char* url_name);
|
||||
static bool IsHttpSchemeURL(const char* url_name);
|
||||
static const char* RemoveScheme(const char* url);
|
||||
static char* DirName(const char* url);
|
||||
static void* MapExecutable(const char* name, intptr_t* file_len);
|
||||
static void* OpenFile(const char* name, bool write);
|
||||
static void ReadFile(const uint8_t** data, intptr_t* file_len, void* stream);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "bin/file.h"
|
||||
#include "bin/lockers.h"
|
||||
#include "bin/utils.h"
|
||||
#include "include/dart_tools_api.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
@ -353,6 +354,7 @@ bool Loader::ProcessResultLocked(Loader* loader, Loader::IOResult* result) {
|
|||
loader->monitor_->Exit();
|
||||
|
||||
Dart_Handle dart_result = Dart_Null();
|
||||
bool reload_extensions = false;
|
||||
|
||||
switch (tag) {
|
||||
case Dart_kImportTag:
|
||||
|
@ -367,6 +369,7 @@ bool Loader::ProcessResultLocked(Loader* loader, Loader::IOResult* result) {
|
|||
case Dart_kScriptTag:
|
||||
if (payload_type == DartUtils::kSnapshotMagicNumber) {
|
||||
dart_result = Dart_LoadScriptFromSnapshot(payload, payload_length);
|
||||
reload_extensions = true;
|
||||
} else if (payload_type == DartUtils::kKernelMagicNumber) {
|
||||
dart_result = Dart_LoadKernel(payload, payload_length);
|
||||
} else {
|
||||
|
@ -385,6 +388,15 @@ bool Loader::ProcessResultLocked(Loader* loader, Loader::IOResult* result) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (reload_extensions) {
|
||||
dart_result = ReloadNativeExtensions();
|
||||
if (Dart_IsError(dart_result)) {
|
||||
// Remember the error if we encountered one.
|
||||
loader->error_ = dart_result;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -437,6 +449,51 @@ void Loader::InitForSnapshot(const char* snapshot_uri) {
|
|||
}
|
||||
|
||||
|
||||
#define RETURN_ERROR(result) \
|
||||
if (Dart_IsError(result)) return result;
|
||||
|
||||
Dart_Handle Loader::ReloadNativeExtensions() {
|
||||
Dart_Handle scheme =
|
||||
Dart_NewStringFromCString(DartUtils::kDartExtensionScheme);
|
||||
Dart_Handle extension_imports = Dart_GetImportsOfScheme(scheme);
|
||||
RETURN_ERROR(extension_imports);
|
||||
|
||||
intptr_t length = -1;
|
||||
Dart_Handle result = Dart_ListLength(extension_imports, &length);
|
||||
RETURN_ERROR(result);
|
||||
Dart_Handle* import_handles = reinterpret_cast<Dart_Handle*>(
|
||||
Dart_ScopeAllocate(sizeof(Dart_Handle) * length));
|
||||
result = Dart_ListGetRange(extension_imports, 0, length, import_handles);
|
||||
RETURN_ERROR(result);
|
||||
for (intptr_t i = 0; i < length; i += 2) {
|
||||
Dart_Handle importer = import_handles[i];
|
||||
Dart_Handle importee = import_handles[i + 1];
|
||||
|
||||
const char* extension_uri = NULL;
|
||||
result = Dart_StringToCString(Dart_LibraryUrl(importee), &extension_uri);
|
||||
RETURN_ERROR(result);
|
||||
const char* extension_path = DartUtils::RemoveScheme(extension_uri);
|
||||
|
||||
const char* lib_uri = NULL;
|
||||
result = Dart_StringToCString(Dart_LibraryUrl(importer), &lib_uri);
|
||||
RETURN_ERROR(result);
|
||||
|
||||
char* lib_path = NULL;
|
||||
if (strncmp(lib_uri, "file://", 7) == 0) {
|
||||
lib_path = DartUtils::DirName(DartUtils::RemoveScheme(lib_uri));
|
||||
} else {
|
||||
lib_path = strdup(lib_uri);
|
||||
}
|
||||
|
||||
result = Extensions::LoadExtension(lib_path, extension_path, importer);
|
||||
free(lib_path);
|
||||
RETURN_ERROR(result);
|
||||
}
|
||||
|
||||
return Dart_True();
|
||||
}
|
||||
|
||||
|
||||
Dart_Handle Loader::LoadUrlContents(Dart_Handle url,
|
||||
uint8_t** payload,
|
||||
intptr_t* payload_length) {
|
||||
|
|
|
@ -22,6 +22,8 @@ class Loader {
|
|||
|
||||
static void InitForSnapshot(const char* snapshot_uri);
|
||||
|
||||
static Dart_Handle ReloadNativeExtensions();
|
||||
|
||||
// Loads contents of the specified url.
|
||||
static Dart_Handle LoadUrlContents(Dart_Handle url,
|
||||
uint8_t** payload,
|
||||
|
|
|
@ -815,6 +815,10 @@ static Dart_Isolate CreateIsolateAndSetupHelper(const char* script_uri,
|
|||
Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
|
||||
Builtin::SetNativeResolver(Builtin::kIOLibrary);
|
||||
}
|
||||
if (run_app_snapshot) {
|
||||
Dart_Handle result = Loader::ReloadNativeExtensions();
|
||||
CHECK_RESULT(result);
|
||||
}
|
||||
|
||||
// Set up the library tag handler for this isolate.
|
||||
Dart_Handle result = Dart_SetLibraryTagHandler(Loader::LibraryTagHandler);
|
||||
|
|
|
@ -2940,6 +2940,19 @@ DART_EXPORT Dart_Handle Dart_LibraryImportLibrary(Dart_Handle library,
|
|||
Dart_Handle import,
|
||||
Dart_Handle prefix);
|
||||
|
||||
|
||||
/**
|
||||
* Returns a flattened list of pairs. The first element in each pair is the
|
||||
* importing library and and the second element is the imported library for each
|
||||
* import in the isolate of a library whose URI's scheme is [scheme].
|
||||
*
|
||||
* Requires there to be a current isolate.
|
||||
*
|
||||
* \return A handle to a list of flattened pairs of importer-importee.
|
||||
*/
|
||||
DART_EXPORT Dart_Handle Dart_GetImportsOfScheme(Dart_Handle scheme);
|
||||
|
||||
|
||||
/**
|
||||
* Called by the embedder to provide the source for a "part of"
|
||||
* directive. This function should be called in response to a
|
||||
|
|
|
@ -156,7 +156,7 @@ class LibraryViewElement extends HtmlElement implements Renderable {
|
|||
new DivElement()
|
||||
..classes = ['content-centered-big']
|
||||
..children = [
|
||||
new HeadingElement.h2()..text = 'ICData',
|
||||
new HeadingElement.h2()..text = 'Library',
|
||||
new HRElement(),
|
||||
new ObjectCommonElement(_isolate, _library, _retainedSizes,
|
||||
_reachableSizes, _references, _retainingPaths, _instances,
|
||||
|
|
|
@ -5718,6 +5718,42 @@ DART_EXPORT Dart_Handle Dart_LibraryImportLibrary(Dart_Handle library,
|
|||
}
|
||||
|
||||
|
||||
DART_EXPORT Dart_Handle Dart_GetImportsOfScheme(Dart_Handle scheme) {
|
||||
DARTSCOPE(Thread::Current());
|
||||
Isolate* I = T->isolate();
|
||||
const String& scheme_vm = Api::UnwrapStringHandle(Z, scheme);
|
||||
if (scheme_vm.IsNull()) {
|
||||
RETURN_TYPE_ERROR(Z, scheme, String);
|
||||
}
|
||||
|
||||
const GrowableObjectArray& libraries =
|
||||
GrowableObjectArray::Handle(Z, I->object_store()->libraries());
|
||||
const GrowableObjectArray& result =
|
||||
GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
|
||||
Library& importer = Library::Handle(Z);
|
||||
Array& imports = Array::Handle(Z);
|
||||
Namespace& ns = Namespace::Handle(Z);
|
||||
Library& importee = Library::Handle(Z);
|
||||
String& importee_uri = String::Handle(Z);
|
||||
for (intptr_t i = 0; i < libraries.Length(); i++) {
|
||||
importer ^= libraries.At(i);
|
||||
imports = importer.imports();
|
||||
for (intptr_t j = 0; j < imports.Length(); j++) {
|
||||
ns ^= imports.At(j);
|
||||
if (ns.IsNull()) continue;
|
||||
importee = ns.library();
|
||||
importee_uri = importee.url();
|
||||
if (importee_uri.StartsWith(scheme_vm)) {
|
||||
result.Add(importer);
|
||||
result.Add(importee);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Api::NewHandle(T, Array::MakeArray(result));
|
||||
}
|
||||
|
||||
|
||||
DART_EXPORT Dart_Handle Dart_LoadSource(Dart_Handle library,
|
||||
Dart_Handle url,
|
||||
Dart_Handle resolved_url,
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) 2016, 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 test program for testing native extensions.
|
||||
|
||||
import 'sample_extension_test_helper.dart';
|
||||
|
||||
void main() {
|
||||
testNativeExtensions("app-jit");
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) 2016, 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 test program for testing native extensions.
|
||||
|
||||
import 'sample_extension_test_helper.dart';
|
||||
|
||||
void main() {
|
||||
testNativeExtensions("script");
|
||||
}
|
|
@ -1,72 +1,11 @@
|
|||
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
||||
// Copyright (c) 2016, 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 test program for testing native extensions.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "package:path/path.dart";
|
||||
|
||||
Future copyFileToDirectory(String file, String directory) {
|
||||
String src = file;
|
||||
String dst = directory;
|
||||
switch (Platform.operatingSystem) {
|
||||
case 'linux':
|
||||
case 'macos':
|
||||
return Process.run('cp', [src, dst]);
|
||||
case 'windows':
|
||||
return Process.run('cmd.exe', ['/C', 'copy $src $dst']);
|
||||
default:
|
||||
Expect.fail('Unknown operating system ${Platform.operatingSystem}');
|
||||
}
|
||||
}
|
||||
|
||||
String getNativeLibraryPath(String buildDirectory) {
|
||||
switch (Platform.operatingSystem) {
|
||||
case 'linux':
|
||||
return join(buildDirectory, 'lib.target', 'libsample_extension.so');
|
||||
case 'macos':
|
||||
return join(buildDirectory, 'libsample_extension.dylib');
|
||||
case 'windows':
|
||||
return join(buildDirectory, 'sample_extension.dll');
|
||||
default:
|
||||
Expect.fail('Unknown operating system ${Platform.operatingSystem}');
|
||||
}
|
||||
}
|
||||
import 'sample_extension_test_helper.dart';
|
||||
|
||||
void main() {
|
||||
String buildDirectory = dirname(Platform.executable);
|
||||
Directory tempDirectory =
|
||||
Directory.systemTemp.createTempSync('sample_extension_');
|
||||
String testDirectory = tempDirectory.path;
|
||||
String sourceDirectory = Platform.script.resolve('..').toFilePath();
|
||||
|
||||
// Copy sample_extension shared library, sample_extension dart files and
|
||||
// sample_extension tests to the temporary test directory.
|
||||
copyFileToDirectory(getNativeLibraryPath(buildDirectory), testDirectory)
|
||||
.then((_) => Future.forEach(['sample_synchronous_extension.dart',
|
||||
'sample_asynchronous_extension.dart',
|
||||
'test_sample_synchronous_extension.dart',
|
||||
'test_sample_asynchronous_extension.dart'],
|
||||
(file) => copyFileToDirectory(join(sourceDirectory, file), testDirectory)
|
||||
))
|
||||
|
||||
.then((_) => Future.forEach(['test_sample_synchronous_extension.dart',
|
||||
'test_sample_asynchronous_extension.dart'],
|
||||
(test) => Process.run(Platform.executable, [join(testDirectory, test)])
|
||||
.then((ProcessResult result) {
|
||||
if (result.exitCode != 0) {
|
||||
print('Failing test: ${join(sourceDirectory, test)}');
|
||||
print('Failing process stdout: ${result.stdout}');
|
||||
print('Failing process stderr: ${result.stderr}');
|
||||
print('End failing process stderr');
|
||||
Expect.fail('Test failed with exit code ${result.exitCode}');
|
||||
}
|
||||
})
|
||||
))
|
||||
.whenComplete(() => tempDirectory.deleteSync(recursive: true));
|
||||
testNativeExtensions(null /* no snapshot */);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) 2013, 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 test program for testing native extensions.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "package:path/path.dart";
|
||||
|
||||
Future copyFileToDirectory(String file, String directory) {
|
||||
String src = file;
|
||||
String dst = directory;
|
||||
switch (Platform.operatingSystem) {
|
||||
case 'linux':
|
||||
case 'macos':
|
||||
return Process.run('cp', [src, dst]);
|
||||
case 'windows':
|
||||
return Process.run('cmd.exe', ['/C', 'copy $src $dst']);
|
||||
default:
|
||||
Expect.fail('Unknown operating system ${Platform.operatingSystem}');
|
||||
}
|
||||
}
|
||||
|
||||
String getNativeLibraryPath(String buildDirectory) {
|
||||
switch (Platform.operatingSystem) {
|
||||
case 'linux':
|
||||
return join(buildDirectory, 'lib.target', 'libsample_extension.so');
|
||||
case 'macos':
|
||||
return join(buildDirectory, 'libsample_extension.dylib');
|
||||
case 'windows':
|
||||
return join(buildDirectory, 'sample_extension.dll');
|
||||
default:
|
||||
Expect.fail('Unknown operating system ${Platform.operatingSystem}');
|
||||
}
|
||||
}
|
||||
|
||||
Future run(String program, List arguments) async {
|
||||
print("+ $program ${arguments.join(' ')}");
|
||||
ProcessResult result = await Process.run(program, arguments);
|
||||
if (result.exitCode != 0) {
|
||||
print('Failing process stdout: ${result.stdout}');
|
||||
print('Failing process stderr: ${result.stderr}');
|
||||
print('End failing process stderr');
|
||||
Expect.fail('Test failed with exit code ${result.exitCode}');
|
||||
}
|
||||
}
|
||||
|
||||
Future testNativeExtensions(String snapshotKind) async {
|
||||
String buildDirectory = dirname(Platform.executable);
|
||||
Directory tempDirectory =
|
||||
Directory.systemTemp.createTempSync('sample_extension_');
|
||||
try {
|
||||
String testDirectory = tempDirectory.path;
|
||||
String sourceDirectory = Platform.script.resolve('..').toFilePath();
|
||||
|
||||
// Copy sample_extension shared library, sample_extension dart files and
|
||||
// sample_extension tests to the temporary test directory.
|
||||
await copyFileToDirectory(getNativeLibraryPath(buildDirectory),
|
||||
testDirectory);
|
||||
for (var file in ['sample_synchronous_extension.dart',
|
||||
'sample_asynchronous_extension.dart',
|
||||
'test_sample_synchronous_extension.dart',
|
||||
'test_sample_asynchronous_extension.dart']) {
|
||||
await copyFileToDirectory(join(sourceDirectory, file), testDirectory);
|
||||
}
|
||||
|
||||
for (var test in ['test_sample_synchronous_extension.dart',
|
||||
'test_sample_asynchronous_extension.dart']) {
|
||||
String script = join(testDirectory, test);
|
||||
String snapshot;
|
||||
if (snapshotKind == null) {
|
||||
snapshot = script;
|
||||
} else {
|
||||
snapshot = join(testDirectory, "$test.snapshot");
|
||||
await run(Platform.executable,
|
||||
['--snapshot=$snapshot',
|
||||
'--snapshot-kind=$snapshotKind',
|
||||
script]);
|
||||
}
|
||||
|
||||
await run(Platform.executable, [snapshot]);
|
||||
}
|
||||
} finally {
|
||||
await tempDirectory.deleteSync(recursive: true);
|
||||
}
|
||||
}
|
|
@ -19,10 +19,7 @@ sample_extension: Crash # Unable to compile UnsupportedError.message.
|
|||
build_dart: Skip
|
||||
|
||||
[ $arch == arm ]
|
||||
sample_extension/test/sample_extension_test: Skip # Issue 14705
|
||||
|
||||
[ $arch == simarm64 ]
|
||||
*: Skip
|
||||
sample_extension/test/*: Skip # Issue 14705
|
||||
|
||||
[ $noopt || $runtime == dart_precompiled || $runtime == dart_app ]
|
||||
sample_extension: Skip # Platform.executable
|
||||
|
|
Loading…
Reference in a new issue