// Copyright (c) 2012, 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. #include "vm/bootstrap.h" #include "include/dart_api.h" #include "vm/bootstrap_natives.h" #include "vm/compiler.h" #include "vm/dart_api_impl.h" #include "vm/object.h" #include "vm/object_store.h" #include "vm/symbols.h" namespace dart { #define INIT_LIBRARY(index, name, source, patch) \ { index, \ "dart:"#name, source, \ "dart:"#name"-patch", patch } \ typedef struct { intptr_t index_; const char* uri_; const char** source_paths_; const char* patch_uri_; const char** patch_paths_; } bootstrap_lib_props; static bootstrap_lib_props bootstrap_libraries[] = { INIT_LIBRARY(ObjectStore::kCore, core, Bootstrap::corelib_source_paths_, Bootstrap::corelib_patch_paths_), INIT_LIBRARY(ObjectStore::kAsync, async, Bootstrap::async_source_paths_, Bootstrap::async_patch_paths_), INIT_LIBRARY(ObjectStore::kConvert, convert, Bootstrap::convert_source_paths_, Bootstrap::convert_patch_paths_), INIT_LIBRARY(ObjectStore::kCollection, collection, Bootstrap::collection_source_paths_, Bootstrap::collection_patch_paths_), INIT_LIBRARY(ObjectStore::kCollectionDev, _collection-dev, Bootstrap::collection_dev_source_paths_, Bootstrap::collection_dev_patch_paths_), INIT_LIBRARY(ObjectStore::kIsolate, isolate, Bootstrap::isolate_source_paths_, Bootstrap::isolate_patch_paths_), INIT_LIBRARY(ObjectStore::kJson, json, Bootstrap::json_source_paths_, NULL), INIT_LIBRARY(ObjectStore::kMath, math, Bootstrap::math_source_paths_, Bootstrap::math_patch_paths_), INIT_LIBRARY(ObjectStore::kMirrors, mirrors, Bootstrap::mirrors_source_paths_, Bootstrap::mirrors_patch_paths_), INIT_LIBRARY(ObjectStore::kTypedData, typed_data, Bootstrap::typed_data_source_paths_, Bootstrap::typed_data_patch_paths_), INIT_LIBRARY(ObjectStore::kUtf, utf, Bootstrap::utf_source_paths_, NULL), { ObjectStore::kNone, NULL, NULL, NULL, NULL } }; static RawString* GetLibrarySource(const Library& lib, const String& uri, bool patch) { // First check if this is a valid boot strap library and find it's index // in the 'bootstrap_libraries' table above. intptr_t index; const String& lib_uri = String::Handle(lib.url()); for (index = 0; bootstrap_libraries[index].index_ != ObjectStore::kNone; ++index) { if (lib_uri.Equals(bootstrap_libraries[index].uri_)) { break; } } if (bootstrap_libraries[index].index_ == ObjectStore::kNone) { return String::null(); // Library is not a boot strap library. } // Try to read the source using the path specified for the uri. const char** source_paths = patch ? bootstrap_libraries[index].patch_paths_ : bootstrap_libraries[index].source_paths_; if (source_paths == NULL) { return String::null(); // No path mapping information exists for library. } const char* source_path = NULL; for (intptr_t i = 0; source_paths[i] != NULL; i += 2) { if (uri.Equals(source_paths[i])) { source_path = source_paths[i + 1]; break; } } if (source_path == NULL) { return String::null(); // Uri does not exist in path mapping information. } Dart_FileOpenCallback file_open = Isolate::file_open_callback(); Dart_FileReadCallback file_read = Isolate::file_read_callback(); Dart_FileCloseCallback file_close = Isolate::file_close_callback(); if (file_open == NULL || file_read == NULL || file_close == NULL) { return String::null(); // File operations are not supported. } void* stream = (*file_open)(source_path, false); if (stream == NULL) { return String::null(); } const uint8_t* utf8_array = NULL; intptr_t file_length = -1; (*file_read)(&utf8_array, &file_length, stream); if (file_length == -1) { return String::null(); } ASSERT(utf8_array != NULL); (*file_close)(stream); return String::FromUTF8(utf8_array, file_length); } static RawError* Compile(const Library& library, const Script& script) { bool update_lib_status = (script.kind() == RawScript::kScriptTag || script.kind() == RawScript::kLibraryTag); if (update_lib_status) { library.SetLoadInProgress(); } const Error& error = Error::Handle(Compiler::Compile(library, script)); if (update_lib_status) { if (error.IsNull()) { library.SetLoaded(); } else { library.SetLoadError(); } } return error.raw(); } static Dart_Handle LoadPartSource(Isolate* isolate, const Library& lib, const String& uri) { const String& part_source = String::Handle( isolate, GetLibrarySource(lib, uri, false)); const String& lib_uri = String::Handle(isolate, lib.url()); if (part_source.IsNull()) { return Dart_NewApiError("Unable to read part file '%s' of library '%s'", uri.ToCString(), lib_uri.ToCString()); } // Prepend the library URI to form a unique script URI for the part. const Array& strings = Array::Handle(isolate, Array::New(3)); strings.SetAt(0, lib_uri); strings.SetAt(1, Symbols::Slash()); strings.SetAt(2, uri); const String& part_uri = String::Handle(isolate, String::ConcatAll(strings)); // Create a script object and compile the part. const Script& part_script = Script::Handle( isolate, Script::New(part_uri, part_source, RawScript::kSourceTag)); const Error& error = Error::Handle(isolate, Compile(lib, part_script)); return Api::NewHandle(isolate, error.raw()); } static Dart_Handle BootstrapLibraryTagHandler(Dart_LibraryTag tag, Dart_Handle library, Dart_Handle uri) { Isolate* isolate = Isolate::Current(); if (!Dart_IsLibrary(library)) { return Dart_NewApiError("not a library"); } if (!Dart_IsString(uri)) { return Dart_NewApiError("uri is not a string"); } if (tag == Dart_kCanonicalizeUrl) { // In the boot strap loader we do not try and do any canonicalization. return uri; } const String& uri_str = Api::UnwrapStringHandle(isolate, uri); ASSERT(!uri_str.IsNull()); if (tag == Dart_kImportTag) { // We expect the core bootstrap libraries to only import other // core bootstrap libraries. // We have precreated all the bootstrap library objects hence // we do not expect to be called back with the tag set to kImportTag. // The bootstrap process explicitly loads all the libraries one by one. return Dart_NewApiError("Invalid import of '%s' in a bootstrap library", uri_str.ToCString()); } ASSERT(tag == Dart_kSourceTag); const Library& lib = Api::UnwrapLibraryHandle(isolate, library); ASSERT(!lib.IsNull()); return LoadPartSource(isolate, lib, uri_str); } static RawError* LoadPatchFiles(Isolate* isolate, const Library& lib, const String& patch_uri, const char** patch_files) { String& patch_file_uri = String::Handle(isolate); String& source = String::Handle(isolate); Script& script = Script::Handle(isolate); Error& error = Error::Handle(isolate); const Array& strings = Array::Handle(isolate, Array::New(3)); strings.SetAt(0, patch_uri); strings.SetAt(1, Symbols::Slash()); for (intptr_t j = 0; patch_files[j] != NULL; j += 2) { patch_file_uri = String::New(patch_files[j]); source = GetLibrarySource(lib, patch_file_uri, true); if (source.IsNull()) { return Api::UnwrapErrorHandle( isolate, Api::NewError("Unable to find dart patch source for %s", patch_file_uri.ToCString())).raw(); } // Prepend the patch library URI to form a unique script URI for the patch. strings.SetAt(2, patch_file_uri); patch_file_uri = String::ConcatAll(strings); script = Script::New(patch_file_uri, source, RawScript::kPatchTag); error = lib.Patch(script); if (!error.IsNull()) { return error.raw(); } } return Error::null(); } RawError* Bootstrap::LoadandCompileScripts() { Isolate* isolate = Isolate::Current(); String& uri = String::Handle(); String& patch_uri = String::Handle(); String& source = String::Handle(); Script& script = Script::Handle(); Library& lib = Library::Handle(); Error& error = Error::Handle(); Dart_LibraryTagHandler saved_tag_handler = isolate->library_tag_handler(); // Set the library tag handler for the isolate to the bootstrap // library tag handler so that we can load all the bootstrap libraries. isolate->set_library_tag_handler(BootstrapLibraryTagHandler); // Enter the Dart Scope as we will be calling back into the library // tag handler when compiling the bootstrap libraries. Dart_EnterScope(); // Create library objects for all the bootstrap libraries. for (intptr_t i = 0; bootstrap_libraries[i].index_ != ObjectStore::kNone; ++i) { uri = Symbols::New(bootstrap_libraries[i].uri_); lib = Library::LookupLibrary(uri); if (lib.IsNull()) { lib = Library::NewLibraryHelper(uri, false); lib.Register(); } isolate->object_store()->set_bootstrap_library( bootstrap_libraries[i].index_, lib); } // Load, compile and patch bootstrap libraries. for (intptr_t i = 0; bootstrap_libraries[i].index_ != ObjectStore::kNone; ++i) { uri = Symbols::New(bootstrap_libraries[i].uri_); lib = Library::LookupLibrary(uri); ASSERT(!lib.IsNull()); source = GetLibrarySource(lib, uri, false); if (source.IsNull()) { error ^= Api::UnwrapErrorHandle( isolate, Api::NewError("Unable to find dart source for %s", uri.ToCString())).raw(); break; } script = Script::New(uri, source, RawScript::kLibraryTag); error = Compile(lib, script); if (!error.IsNull()) { break; } // If a patch exists, load and patch the script. if (bootstrap_libraries[i].patch_paths_ != NULL) { patch_uri = Symbols::New(bootstrap_libraries[i].patch_uri_); error = LoadPatchFiles(isolate, lib, patch_uri, bootstrap_libraries[i].patch_paths_); if (!error.IsNull()) { break; } } } if (error.IsNull()) { SetupNativeResolver(); } // Exit the Dart scope. Dart_ExitScope(); // Restore the library tag handler for the isolate. isolate->set_library_tag_handler(saved_tag_handler); return error.raw(); } } // namespace dart