1// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "bin/loader.h"
6
7#include "bin/builtin.h"
8#include "bin/dartutils.h"
9#include "bin/dfe.h"
10#include "bin/error_exit.h"
11#include "bin/extensions.h"
12#include "bin/file.h"
13#include "bin/gzip.h"
14#include "bin/lockers.h"
15#include "bin/snapshot_utils.h"
16#include "bin/utils.h"
17#include "include/dart_tools_api.h"
18#include "platform/growable_array.h"
19
20namespace dart {
21namespace bin {
22
23#if !defined(DART_PRECOMPILED_RUNTIME)
24extern DFE dfe;
25#endif
26
27Dart_Handle Loader::InitForSnapshot(const char* snapshot_uri,
28 IsolateData* isolate_data) {
29 ASSERT(isolate_data != NULL);
30
31 return Loader::Init(isolate_data->packages_file(),
32 DartUtils::original_working_directory, snapshot_uri);
33}
34
35// Initialize package resolution state.
36Dart_Handle Loader::Init(const char* packages_file,
37 const char* working_directory,
38 const char* root_script_uri) {
39 const int kNumArgs = 3;
40 Dart_Handle dart_args[kNumArgs];
41 dart_args[0] = (packages_file == NULL)
42 ? Dart_Null()
43 : Dart_NewStringFromCString(packages_file);
44 dart_args[1] = Dart_NewStringFromCString(working_directory);
45 dart_args[2] = (root_script_uri == NULL)
46 ? Dart_Null()
47 : Dart_NewStringFromCString(root_script_uri);
48 return Dart_Invoke(DartUtils::LookupBuiltinLib(),
49 DartUtils::NewString("_Init"), kNumArgs, dart_args);
50}
51
52static bool PathContainsSeparator(const char* path) {
53 return (strchr(path, '/') != NULL) ||
54 ((strncmp(File::PathSeparator(), "/", 1) != 0) &&
55 (strstr(path, File::PathSeparator()) != NULL));
56}
57
58#define RETURN_ERROR(result) \
59 if (Dart_IsError(result)) return result;
60
61Dart_Handle Loader::LoadImportExtension(const char* url_string,
62 Dart_Handle library) {
63 const char* lib_uri_str = NULL;
64 Dart_Handle lib_uri = Dart_LibraryResolvedUrl(library);
65 ASSERT(!Dart_IsError(lib_uri));
66 Dart_Handle result = Dart_StringToCString(lib_uri, &lib_uri_str);
67 RETURN_ERROR(result);
68
69 UriDecoder decoder(lib_uri_str);
70 lib_uri_str = decoder.decoded();
71
72 if (strncmp(lib_uri_str, "http://", 7) == 0 ||
73 strncmp(lib_uri_str, "https://", 8) == 0 ||
74 strncmp(lib_uri_str, "data://", 7) == 0) {
75 return DartUtils::NewError(
76 "Cannot load native extensions over http: or https: or data: %s",
77 lib_uri_str);
78 }
79
80 char* lib_path = NULL;
81 if (strncmp(lib_uri_str, "file://", 7) == 0) {
82 lib_path = DartUtils::DirName(lib_uri_str + 7);
83 } else {
84 lib_path = Utils::StrDup(lib_uri_str);
85 }
86
87 const char* path = DartUtils::RemoveScheme(url_string);
88 if (!File::IsAbsolutePath(path) && PathContainsSeparator(path)) {
89 free(lib_path);
90 return DartUtils::NewError(
91 "Native extension path must be absolute, or simply the file name: %s",
92 path);
93 }
94
95 result = Extensions::LoadExtension(lib_path, path, library);
96 free(lib_path);
97 return result;
98}
99
100Dart_Handle Loader::ReloadNativeExtensions() {
101 Dart_Handle scheme =
102 Dart_NewStringFromCString(DartUtils::kDartExtensionScheme);
103 Dart_Handle extension_imports = Dart_GetImportsOfScheme(scheme);
104 RETURN_ERROR(extension_imports);
105
106 intptr_t length = -1;
107 Dart_Handle result = Dart_ListLength(extension_imports, &length);
108 RETURN_ERROR(result);
109 Dart_Handle* import_handles = reinterpret_cast<Dart_Handle*>(
110 Dart_ScopeAllocate(sizeof(Dart_Handle) * length));
111 result = Dart_ListGetRange(extension_imports, 0, length, import_handles);
112 RETURN_ERROR(result);
113 for (intptr_t i = 0; i < length; i += 2) {
114 Dart_Handle importer = import_handles[i];
115 Dart_Handle importee = import_handles[i + 1];
116
117 const char* extension_uri = NULL;
118 result = Dart_StringToCString(Dart_LibraryUrl(importee), &extension_uri);
119 RETURN_ERROR(result);
120 const char* extension_path = DartUtils::RemoveScheme(extension_uri);
121
122 const char* lib_uri = NULL;
123 result = Dart_StringToCString(Dart_LibraryUrl(importer), &lib_uri);
124 RETURN_ERROR(result);
125
126 char* lib_path = NULL;
127 if (strncmp(lib_uri, "file://", 7) == 0) {
128 lib_path = DartUtils::DirName(DartUtils::RemoveScheme(lib_uri));
129 } else {
130 lib_path = Utils::StrDup(lib_uri);
131 }
132
133 result = Extensions::LoadExtension(lib_path, extension_path, importer);
134 free(lib_path);
135 RETURN_ERROR(result);
136 }
137
138 return Dart_True();
139}
140
141#if !defined(DART_PRECOMPILED_RUNTIME)
142static void MallocFinalizer(void* isolate_callback_data, void* peer) {
143 free(peer);
144}
145#endif
146
147Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag,
148 Dart_Handle library,
149 Dart_Handle url) {
150 const char* url_string = NULL;
151 Dart_Handle result = Dart_StringToCString(url, &url_string);
152 if (Dart_IsError(result)) {
153 return result;
154 }
155 if (tag == Dart_kCanonicalizeUrl) {
156 Dart_Handle library_url = Dart_LibraryUrl(library);
157 if (Dart_IsError(library_url)) {
158 return library_url;
159 }
160 const char* library_url_string = NULL;
161 result = Dart_StringToCString(library_url, &library_url_string);
162 if (Dart_IsError(result)) {
163 return result;
164 }
165 bool is_dart_scheme_url = DartUtils::IsDartSchemeURL(url_string);
166 bool is_dart_library = DartUtils::IsDartSchemeURL(library_url_string);
167 if (is_dart_scheme_url || is_dart_library) {
168 return url;
169 }
170 return Dart_DefaultCanonicalizeUrl(library_url, url);
171 }
172#if !defined(DART_PRECOMPILED_RUNTIME)
173 if (tag == Dart_kKernelTag) {
174 uint8_t* kernel_buffer = NULL;
175 intptr_t kernel_buffer_size = 0;
176 if (!DFE::TryReadKernelFile(url_string, &kernel_buffer,
177 &kernel_buffer_size)) {
178 return DartUtils::NewError("'%s' is not a kernel file", url_string);
179 }
180 result = Dart_NewExternalTypedData(Dart_TypedData_kUint8, kernel_buffer,
181 kernel_buffer_size);
182 Dart_NewFinalizableHandle(result, kernel_buffer, kernel_buffer_size,
183 MallocFinalizer);
184 return result;
185 }
186 if (tag == Dart_kImportExtensionTag) {
187 if (!DartUtils::IsDartExtensionSchemeURL(url_string)) {
188 return DartUtils::NewError(
189 "Native extensions must use the dart-ext: scheme : %s", url_string);
190 }
191 return Loader::LoadImportExtension(url_string, library);
192 }
193 if (dfe.CanUseDartFrontend() && dfe.UseDartFrontend() &&
194 (tag == Dart_kImportTag)) {
195 // E.g., IsolateMirror.loadUri.
196 char* error = NULL;
197 int exit_code = 0;
198 uint8_t* kernel_buffer = NULL;
199 intptr_t kernel_buffer_size = -1;
200 dfe.CompileAndReadScript(url_string, &kernel_buffer, &kernel_buffer_size,
201 &error, &exit_code, NULL);
202 if (exit_code == 0) {
203 return Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size);
204 } else if (exit_code == kCompilationErrorExitCode) {
205 Dart_Handle result = Dart_NewCompilationError(error);
206 free(error);
207 return result;
208 } else {
209 Dart_Handle result = Dart_NewApiError(error);
210 free(error);
211 return result;
212 }
213 }
214 return DartUtils::NewError("Invalid tag : %d '%s'", tag, url_string);
215#else // !defined(DART_PRECOMPILED_RUNTIME)
216 return DartUtils::NewError("Unimplemented tag : %d '%s'", tag, url_string);
217#endif // !defined(DART_PRECOMPILED_RUNTIME)
218}
219
220Dart_Handle Loader::DeferredLoadHandler(intptr_t loading_unit_id) {
221 // A synchronous implementation. An asynchronous implementation would be
222 // better, but the standalone embedder only implements AOT for testing.
223
224 auto isolate_group_data =
225 reinterpret_cast<IsolateGroupData*>(Dart_CurrentIsolateGroupData());
226 char* unit_url = Utils::SCreate(
227 "%s-%" Pd ".part.so", isolate_group_data->script_url, loading_unit_id);
228
229 AppSnapshot* loading_unit_snapshot = Snapshot::TryReadAppSnapshot(unit_url);
230 Dart_Handle result;
231 if (loading_unit_snapshot != nullptr) {
232 isolate_group_data->AddLoadingUnit(loading_unit_snapshot);
233 const uint8_t* isolate_snapshot_data = nullptr;
234 const uint8_t* isolate_snapshot_instructions = nullptr;
235 const uint8_t* ignore_vm_snapshot_data;
236 const uint8_t* ignore_vm_snapshot_instructions;
237 loading_unit_snapshot->SetBuffers(
238 &ignore_vm_snapshot_data, &ignore_vm_snapshot_instructions,
239 &isolate_snapshot_data, &isolate_snapshot_instructions);
240 result = Dart_DeferredLoadComplete(loading_unit_id, isolate_snapshot_data,
241 isolate_snapshot_instructions);
242 if (Dart_IsApiError(result)) {
243 result =
244 Dart_DeferredLoadCompleteError(loading_unit_id, Dart_GetError(result),
245 /*transient*/ false);
246 }
247 } else {
248 char* error_message = Utils::SCreate("Failed to load %s", unit_url);
249 result = Dart_DeferredLoadCompleteError(loading_unit_id, error_message,
250 /*transient*/ false);
251 free(error_message);
252 }
253
254 free(unit_url);
255 return result;
256}
257
258void Loader::InitOnce() {
259}
260
261} // namespace bin
262} // namespace dart
263