dart-sdk/runtime/vm/bootstrap.cc

204 lines
7.1 KiB
C++
Raw Normal View History

// 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"
[vm/bytecode] Bootstrapping VM from bytecode Previously, core snapshot was generated from AST (because --enable-interpreter/--use-bytecode-compiler was not specified when building core snapshot). As the result, CL https://dart.googlesource.com/sdk/+/da8cb470cc94830a98d49532e8d5d1a5b3d80f8b which declared libraries in bytecode also removed bytecode entirely from core snapshot in Dart SDK. This CL enables bytecode by default if --bytecode argument is specified for gn.py. This enables JIT compiler from bytecode (interpreter is still disabled by default but can be enabled using --enable-interpreter). Core snapshot and other snapshots now have bytecode. This change revealed a bunch of bugs which are fixed in this CL: * _Closure fields were treated as unboxing candidates which triggered assertion in LoadFieldTOS in interpreter. * Several places should load class declarations if they are not loaded yet. * Canonicalization of TypeRef objects which are not fully initialized may cause duplicate entries in the hash table of canonical TypeArguments. This triggers assertions when hash table is rehashed. The solution is to avoid canonicalization of non-root recursive types and recursive type arguments. Also, TypeRef::Canonicalize and TypeRef::Hash are reverted to assert and work only if type was set. * Native wrapper classes are eagerly stamped as type-finalized which caused assertion failures when reading their class declarations from bytecode. * When building flow graph for FFI trampolines kernel offset of library (which is now declared in bytecode) was queried. Added special case to Function::KernelDataProgramOffset(). * In interpreter-only mode with simulator (e.g. SIMARM64) if simulator is not called before code is interrupted with stack overflow check, simulator returns get_sp() = 0, which was treated as stack overflow. * test standalone_2/io/platform_resolved_executable_test.dart spawns sub-process but it didn't pass VM options. Change-Id: I81bc4f1a4c6725cfa246a435ebe5d8abe43abc67 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107199 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Régis Crelier <regis@google.com>
2019-06-26 18:25:26 +00:00
#include <memory>
#include "include/dart_api.h"
#include "vm/class_finalizer.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/dart_api_impl.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/kernel.h"
#include "vm/kernel_loader.h"
#endif
#include "vm/longjump.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/symbols.h"
namespace dart {
struct BootstrapLibProps {
ObjectStore::BootstrapLibraryId index;
const char* uri;
};
enum { kPathsUriOffset = 0, kPathsSourceOffset = 1, kPathsEntryLength = 2 };
#if !defined(DART_PRECOMPILED_RUNTIME)
#define MAKE_PROPERTIES(CamelName, name) \
{ObjectStore::k##CamelName, "dart:" #name},
static const BootstrapLibProps bootstrap_libraries[] = {
FOR_EACH_BOOTSTRAP_LIBRARY(MAKE_PROPERTIES)};
#undef MAKE_PROPERTIES
static constexpr intptr_t kBootstrapLibraryCount =
ARRAY_SIZE(bootstrap_libraries);
static void Finish(Thread* thread) {
Bootstrap::SetupNativeResolver();
if (!ClassFinalizer::ProcessPendingClasses()) {
FATAL("Error in class finalization during bootstrapping.");
}
// Eagerly compile the _Closure class as it is the class of all closure
// instances. This allows us to just finalize function types without going
// through the hoops of trying to compile their scope class.
ObjectStore* object_store = thread->isolate_group()->object_store();
Zone* zone = thread->zone();
Class& cls = Class::Handle(zone, object_store->closure_class());
cls.EnsureIsFinalized(thread);
// Make sure _Closure fields are not marked as unboxed as they are accessed
// with plain loads.
[vm/bytecode] Bootstrapping VM from bytecode Previously, core snapshot was generated from AST (because --enable-interpreter/--use-bytecode-compiler was not specified when building core snapshot). As the result, CL https://dart.googlesource.com/sdk/+/da8cb470cc94830a98d49532e8d5d1a5b3d80f8b which declared libraries in bytecode also removed bytecode entirely from core snapshot in Dart SDK. This CL enables bytecode by default if --bytecode argument is specified for gn.py. This enables JIT compiler from bytecode (interpreter is still disabled by default but can be enabled using --enable-interpreter). Core snapshot and other snapshots now have bytecode. This change revealed a bunch of bugs which are fixed in this CL: * _Closure fields were treated as unboxing candidates which triggered assertion in LoadFieldTOS in interpreter. * Several places should load class declarations if they are not loaded yet. * Canonicalization of TypeRef objects which are not fully initialized may cause duplicate entries in the hash table of canonical TypeArguments. This triggers assertions when hash table is rehashed. The solution is to avoid canonicalization of non-root recursive types and recursive type arguments. Also, TypeRef::Canonicalize and TypeRef::Hash are reverted to assert and work only if type was set. * Native wrapper classes are eagerly stamped as type-finalized which caused assertion failures when reading their class declarations from bytecode. * When building flow graph for FFI trampolines kernel offset of library (which is now declared in bytecode) was queried. Added special case to Function::KernelDataProgramOffset(). * In interpreter-only mode with simulator (e.g. SIMARM64) if simulator is not called before code is interrupted with stack overflow check, simulator returns get_sp() = 0, which was treated as stack overflow. * test standalone_2/io/platform_resolved_executable_test.dart spawns sub-process but it didn't pass VM options. Change-Id: I81bc4f1a4c6725cfa246a435ebe5d8abe43abc67 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107199 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Régis Crelier <regis@google.com>
2019-06-26 18:25:26 +00:00
const Array& fields = Array::Handle(zone, cls.fields());
Field& field = Field::Handle(zone);
for (intptr_t i = 0; i < fields.Length(); ++i) {
field ^= fields.At(i);
field.set_is_unboxed(false);
[vm/bytecode] Bootstrapping VM from bytecode Previously, core snapshot was generated from AST (because --enable-interpreter/--use-bytecode-compiler was not specified when building core snapshot). As the result, CL https://dart.googlesource.com/sdk/+/da8cb470cc94830a98d49532e8d5d1a5b3d80f8b which declared libraries in bytecode also removed bytecode entirely from core snapshot in Dart SDK. This CL enables bytecode by default if --bytecode argument is specified for gn.py. This enables JIT compiler from bytecode (interpreter is still disabled by default but can be enabled using --enable-interpreter). Core snapshot and other snapshots now have bytecode. This change revealed a bunch of bugs which are fixed in this CL: * _Closure fields were treated as unboxing candidates which triggered assertion in LoadFieldTOS in interpreter. * Several places should load class declarations if they are not loaded yet. * Canonicalization of TypeRef objects which are not fully initialized may cause duplicate entries in the hash table of canonical TypeArguments. This triggers assertions when hash table is rehashed. The solution is to avoid canonicalization of non-root recursive types and recursive type arguments. Also, TypeRef::Canonicalize and TypeRef::Hash are reverted to assert and work only if type was set. * Native wrapper classes are eagerly stamped as type-finalized which caused assertion failures when reading their class declarations from bytecode. * When building flow graph for FFI trampolines kernel offset of library (which is now declared in bytecode) was queried. Added special case to Function::KernelDataProgramOffset(). * In interpreter-only mode with simulator (e.g. SIMARM64) if simulator is not called before code is interrupted with stack overflow check, simulator returns get_sp() = 0, which was treated as stack overflow. * test standalone_2/io/platform_resolved_executable_test.dart spawns sub-process but it didn't pass VM options. Change-Id: I81bc4f1a4c6725cfa246a435ebe5d8abe43abc67 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107199 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Régis Crelier <regis@google.com>
2019-06-26 18:25:26 +00:00
}
// _Closure._hash field should be explicitly marked as nullable because
// VM creates instances of _Closure without compiling its constructors,
// so it won't get nullability info from a constructor.
field ^= fields.At(fields.Length() - 1);
// Note that UserVisibleName depends on --show-internal-names.
ASSERT(strncmp(field.UserVisibleNameCString(), "_hash", 5) == 0);
field.RecordStore(Object::null_object());
[vm/bytecode] Bootstrapping VM from bytecode Previously, core snapshot was generated from AST (because --enable-interpreter/--use-bytecode-compiler was not specified when building core snapshot). As the result, CL https://dart.googlesource.com/sdk/+/da8cb470cc94830a98d49532e8d5d1a5b3d80f8b which declared libraries in bytecode also removed bytecode entirely from core snapshot in Dart SDK. This CL enables bytecode by default if --bytecode argument is specified for gn.py. This enables JIT compiler from bytecode (interpreter is still disabled by default but can be enabled using --enable-interpreter). Core snapshot and other snapshots now have bytecode. This change revealed a bunch of bugs which are fixed in this CL: * _Closure fields were treated as unboxing candidates which triggered assertion in LoadFieldTOS in interpreter. * Several places should load class declarations if they are not loaded yet. * Canonicalization of TypeRef objects which are not fully initialized may cause duplicate entries in the hash table of canonical TypeArguments. This triggers assertions when hash table is rehashed. The solution is to avoid canonicalization of non-root recursive types and recursive type arguments. Also, TypeRef::Canonicalize and TypeRef::Hash are reverted to assert and work only if type was set. * Native wrapper classes are eagerly stamped as type-finalized which caused assertion failures when reading their class declarations from bytecode. * When building flow graph for FFI trampolines kernel offset of library (which is now declared in bytecode) was queried. Added special case to Function::KernelDataProgramOffset(). * In interpreter-only mode with simulator (e.g. SIMARM64) if simulator is not called before code is interrupted with stack overflow check, simulator returns get_sp() = 0, which was treated as stack overflow. * test standalone_2/io/platform_resolved_executable_test.dart spawns sub-process but it didn't pass VM options. Change-Id: I81bc4f1a4c6725cfa246a435ebe5d8abe43abc67 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107199 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Régis Crelier <regis@google.com>
2019-06-26 18:25:26 +00:00
#if defined(DEBUG)
// Verify that closure field offsets are identical in Dart and C++.
ASSERT(fields.Length() == 6);
field ^= fields.At(0);
ASSERT(field.HostOffset() == Closure::instantiator_type_arguments_offset());
field ^= fields.At(1);
ASSERT(field.HostOffset() == Closure::function_type_arguments_offset());
field ^= fields.At(2);
ASSERT(field.HostOffset() == Closure::delayed_type_arguments_offset());
field ^= fields.At(3);
ASSERT(field.HostOffset() == Closure::function_offset());
field ^= fields.At(4);
ASSERT(field.HostOffset() == Closure::context_offset());
field ^= fields.At(5);
ASSERT(field.HostOffset() == Closure::hash_offset());
#endif // defined(DEBUG)
// Eagerly compile to avoid repeated checks when loading constants or
// serializing.
cls = object_store->null_class();
cls.EnsureIsFinalized(thread);
cls = object_store->bool_class();
cls.EnsureIsFinalized(thread);
cls = object_store->array_class();
cls.EnsureIsFinalized(thread);
cls = object_store->immutable_array_class();
cls.EnsureIsFinalized(thread);
cls = object_store->map_impl_class();
cls.EnsureIsFinalized(thread);
cls = object_store->const_map_impl_class();
cls.EnsureIsFinalized(thread);
cls = object_store->set_impl_class();
cls.EnsureIsFinalized(thread);
cls = object_store->const_set_impl_class();
cls.EnsureIsFinalized(thread);
}
static ErrorPtr BootstrapFromKernel(Thread* thread,
const uint8_t* kernel_buffer,
intptr_t kernel_buffer_size) {
Zone* zone = thread->zone();
const char* error = nullptr;
std::unique_ptr<kernel::Program> program = kernel::Program::ReadFromBuffer(
Revert "[vm/kernel] Use GC-tracked ExternalTypedData/TypedDataView for kernel buffers" This reverts commit ab6aeaa106ecdc8c8a8793aaaa3e6dce38456d5a. Revert "[vm/compiler] Speed up the compiler part which deals with kernel reading up in DEBUG mode" This reverts commit b316210d94dece7d34cbe69f8f9e2d81de026330. Reason for revert: regression of snapshot sizes (DNO-599). Original change's description: > [vm/kernel] Use GC-tracked ExternalTypedData/TypedDataView for kernel buffers > > Until now we often leaked kernel buffers (e.g. hot reload buffers) because various > objects were referencing ExternalTypedData objects pointing into the middle of > c-allocated memory. This made it impossible for the GC to determine when the last > reference is gone. > > This CL ensures that the actual buffers are *always* made available via > ExternalTypedData and any inner pointers into it are created via TypedDataViews. > > The embedder guarantees to the free kernel buffers it has provided to: > - Dart_CreateIsolateFromKernel > - Dart_LoadScriptFromKernel > - Dart_LoadLibraryFromKernel > - Dart_SetDartLibrarySourcesKernel > on isolate shutdown. > > All other kernel buffers will get a finalizer attached, which ensures the > kernel buffers get freed by the GC once they are no longer referenced: > - Kernel blobs for expression evaluation > - Kernel blobs for Hot-Reload > - Kernel blobs for cc tests > > Fixes https://github.com/dart-lang/sdk/issues/33973 > Fixes https://github.com/dart-lang/sdk/issues/36857 > Issue https://github.com/dart-lang/sdk/issues/37030 > > Change-Id: I1cc410c94c0f4b229413e793728a261afcb10aaf > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/103130 > Reviewed-by: Ryan Macnak <rmacnak@google.com> > Commit-Queue: Martin Kustermann <kustermann@google.com> TBR=kustermann@google.com,rmacnak@google.com # Not skipping CQ checks because original CL landed > 1 day ago. Change-Id: I49715d2400f4a5c8806b7d6a2912b7258f671a0a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/104343 Reviewed-by: Alexander Markov <alexmarkov@google.com> Reviewed-by: Siva Annamalai <asiva@google.com> Auto-Submit: Alexander Markov <alexmarkov@google.com>
2019-05-31 22:15:51 +00:00
kernel_buffer, kernel_buffer_size, &error);
if (program == nullptr) {
const intptr_t kMessageBufferSize = 512;
char message_buffer[kMessageBufferSize];
Utils::SNPrint(message_buffer, kMessageBufferSize,
"Can't load Kernel binary: %s.", error);
const String& msg = String::Handle(String::New(message_buffer, Heap::kOld));
return ApiError::New(msg, Heap::kOld);
}
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
kernel::KernelLoader loader(program.get(), /*uri_to_source_table=*/nullptr);
auto isolate_group = thread->isolate_group();
if (isolate_group->obfuscate()) {
loader.ReadObfuscationProhibitions();
}
// Load the bootstrap libraries in order (see object_store.h).
Library& library = Library::Handle(zone);
for (intptr_t i = 0; i < kBootstrapLibraryCount; ++i) {
ObjectStore::BootstrapLibraryId id = bootstrap_libraries[i].index;
library = isolate_group->object_store()->bootstrap_library(id);
loader.LoadLibrary(library);
}
// Finish bootstrapping, including class finalization.
Finish(thread);
[vm] Move main ObjectStore initialization right after bootstrapping but before loading user classes This CL fixes AOT failures that happened after [0] landed. That code removed lookup code for the `future_class()` in the `ObjectStore::LazyInit*()` methods and replaced it with an assert instead. The change was correct, since the lazy members should be initialized on-demand - after the core, non-lazy members. => Though this seemed to not be the case in AOT, which hit the assert. The reason [0] only caused failures in AOT is because in JIT the VM is bootstrapped only from the vm_platform.dill file and as a secondary embedder call the application.dill file is loaded. Yet in AOT we have a combined full_application.dill which will all be loaded during bootstrapping. That has caused the application to be loaded before `ObjectStore::InitKnownObjects()` was invoked. The initialization of [ObjectStore] which contains common core library classes/functions/fields should happen before we use the kernel loader to load user classes (since general kernel loading depends on the [ObjectStore] being populated). This also ensures that `ObjectStore::InitKnownObjects()` will be called before `ObjectStore::LazyInit*()` - since they depend on the former having run (e.g. that the non-lazy `future_class()` member of `ObjectStore` was set). [0] https://dart-review.googlesource.com/c/sdk/+/206782 TEST=Fixes AOT builders. Change-Id: I0861d1a2f39effbcea08d7796742845b874a0084 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/207002 Reviewed-by: Tess Strickland <sstrickl@google.com> Commit-Queue: Martin Kustermann <kustermann@google.com>
2021-07-15 08:39:50 +00:00
isolate_group->object_store()->InitKnownObjects();
// The platform binary may contain other libraries (e.g., dart:_builtin or
// dart:io) that will not be bundled with application. Load them now.
const Object& result = Object::Handle(zone, loader.LoadProgram());
program.reset();
if (result.IsError()) {
return Error::Cast(result).ptr();
}
if (FLAG_precompiled_mode) {
loader.ReadLoadingUnits();
}
return Error::null();
}
// Either class finalization failed or we caught a compile-time error.
// In both cases sticky error would be set.
return Thread::Current()->StealStickyError();
}
ErrorPtr Bootstrap::DoBootstrapping(const uint8_t* kernel_buffer,
intptr_t kernel_buffer_size) {
Thread* thread = Thread::Current();
auto isolate_group = thread->isolate_group();
Zone* zone = thread->zone();
String& uri = String::Handle(zone);
Library& lib = Library::Handle(zone);
HANDLESCOPE(thread);
// Ensure there are library objects for all the bootstrap libraries.
for (intptr_t i = 0; i < kBootstrapLibraryCount; ++i) {
ObjectStore::BootstrapLibraryId id = bootstrap_libraries[i].index;
uri = Symbols::New(thread, bootstrap_libraries[i].uri);
lib = isolate_group->object_store()->bootstrap_library(id);
ASSERT(lib.ptr() == Library::LookupLibrary(thread, uri));
if (lib.IsNull()) {
lib = Library::NewLibraryHelper(uri, false);
lib.SetLoadRequested();
lib.Register(thread);
isolate_group->object_store()->set_bootstrap_library(id, lib);
}
}
return BootstrapFromKernel(thread, kernel_buffer, kernel_buffer_size);
}
#else
ErrorPtr Bootstrap::DoBootstrapping(const uint8_t* kernel_buffer,
intptr_t kernel_buffer_size) {
UNREACHABLE();
return Error::null();
}
#endif
} // namespace dart