diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc index b7616aab820..89a5add9d1c 100644 --- a/runtime/bin/run_vm_tests.cc +++ b/runtime/bin/run_vm_tests.cc @@ -150,8 +150,15 @@ static Dart_Isolate CreateIsolateAndSetup(const char* script_uri, isolate = Dart_CreateIsolate( DART_KERNEL_ISOLATE_NAME, main, isolate_snapshot_data, isolate_snapshot_instructions, NULL, NULL, flags, isolate_data, error); + if (*error != NULL) { + free(*error); + *error = NULL; + } } if (isolate == NULL) { + delete isolate_data; + isolate_data = NULL; + bin::dfe.Init(); bin::dfe.LoadKernelService(&kernel_service_buffer, &kernel_service_buffer_size); @@ -286,6 +293,10 @@ static int Main(int argc, const char** argv) { ASSERT(error == NULL); } + TesterState::vm_snapshot_data = dart::bin::vm_snapshot_data; + TesterState::create_callback = CreateIsolateAndSetup; + TesterState::cleanup_callback = CleanupIsolate; + error = Dart::InitOnce( dart::bin::vm_snapshot_data, dart::bin::vm_snapshot_instructions, CreateIsolateAndSetup /* create */, NULL /* shutdown */, @@ -304,9 +315,10 @@ static int Main(int argc, const char** argv) { error = Dart::Cleanup(); ASSERT(error == NULL); + TestCaseBase::RunAllRaw(); + bin::EventHandler::Stop(); - TestCaseBase::RunAllRaw(); // Print a warning message if no tests or benchmarks were matched. if (run_matches == 0) { bin::Log::PrintErr("No tests matched: %s\n", run_filter); diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status index dffdd8e9892..fcf7c0f2859 100644 --- a/runtime/tests/vm/vm.status +++ b/runtime/tests/vm/vm.status @@ -146,7 +146,6 @@ dart/data_uri_import_test/wrongmime: Crash [ $arch == x64 && ($compiler == dartk || $compiler == dartkb) && $system == windows && $strong ] cc/Profiler_BasicSourcePosition: Fail # http://dartbug.com/33224 cc/Profiler_CodeTicks: Fail # dartbug.com/33337 - [ $arch == ia32 && $compiler != dartk && $compiler != dartkp && $compiler != dartkb && $system == windows && $runtime == vm && $mode == debug ] cc/BitTestImmediate: Crash # dartbug.com/34252 diff --git a/runtime/vm/code_observers.cc b/runtime/vm/code_observers.cc index d8a9de9f8c4..c1d982a63b1 100644 --- a/runtime/vm/code_observers.cc +++ b/runtime/vm/code_observers.cc @@ -47,7 +47,7 @@ bool CodeObservers::AreActive() { return false; } -void CodeObservers::DeleteAll() { +void CodeObservers::Cleanup() { for (intptr_t i = 0; i < observers_length_; i++) { delete observers_[i]; } @@ -57,8 +57,9 @@ void CodeObservers::DeleteAll() { } void CodeObservers::InitOnce() { - ASSERT(mutex_ == NULL); - mutex_ = new Mutex(); + if (mutex_ == NULL) { + mutex_ = new Mutex(); + } ASSERT(mutex_ != NULL); OS::RegisterCodeObservers(); } diff --git a/runtime/vm/code_observers.h b/runtime/vm/code_observers.h index f789675f336..f0d856b026a 100644 --- a/runtime/vm/code_observers.h +++ b/runtime/vm/code_observers.h @@ -68,7 +68,7 @@ class CodeObservers : public AllStatic { // Returns true if there is at least one active code observer. static bool AreActive(); - static void DeleteAll(); + static void Cleanup(); static Mutex* mutex() { return mutex_; } diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc index 8eb358665b1..ae91b3e8323 100644 --- a/runtime/vm/compiler_test.cc +++ b/runtime/vm/compiler_test.cc @@ -195,6 +195,7 @@ TEST_CASE(EvalExpression) { val = Instance::Cast(obj).EvaluateCompiledExpression( receiver_cls, kernel_bytes, kernel_length, Array::empty_array(), Array::empty_array(), TypeArguments::null_type_arguments()); + free(const_cast(kernel_bytes)); } EXPECT(!val.IsNull()); EXPECT(!val.IsError()); diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc index dcc1ac8af9f..a34ee6c18dc 100644 --- a/runtime/vm/dart.cc +++ b/runtime/vm/dart.cc @@ -176,7 +176,7 @@ char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot, Api::InitOnce(); NativeSymbolResolver::InitOnce(); NOT_IN_PRODUCT(Profiler::InitOnce()); - SemiSpace::InitOnce(); + SemiSpace::Init(); NOT_IN_PRODUCT(Metric::InitOnce()); StoreBuffer::InitOnce(); MarkingStack::InitOnce(); @@ -454,6 +454,7 @@ const char* Dart::Cleanup() { WaitForIsolateShutdown(); IdleNotifier::Stop(); + // Shutdown the thread pool. On return, all thread pool threads have exited. if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleting thread pool\n", @@ -462,6 +463,10 @@ const char* Dart::Cleanup() { delete thread_pool_; thread_pool_ = NULL; + Api::Cleanup(); + delete predefined_handles_; + predefined_handles_ = NULL; + // Disable creation of any new OSThread structures which means no more new // threads can do an EnterIsolate. This must come after isolate shutdown // because new threads may need to be spawned to shutdown the isolates. @@ -485,12 +490,18 @@ const char* Dart::Cleanup() { ShutdownIsolate(); vm_isolate_ = NULL; ASSERT(Isolate::IsolateListLength() == 0); + PortMap::Cleanup(); IdleNotifier::Cleanup(); - TargetCPUFeatures::Cleanup(); MarkingStack::ShutDown(); StoreBuffer::ShutDown(); - + MarkingStack::ShutDown(); + Object::Cleanup(); + SemiSpace::Cleanup(); +#if !defined(DART_PRECOMPILED_RUNTIME) + // Stubs are generated when not precompiled, clean them up. + StubCode::Cleanup(); +#endif // Delete the current thread's TLS and set it's TLS to null. // If it is the last thread then the destructor would call // OSThread::Cleanup. @@ -506,7 +517,7 @@ const char* Dart::Cleanup() { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleting code observers\n", UptimeMillis()); } - NOT_IN_PRODUCT(CodeObservers::DeleteAll()); + NOT_IN_PRODUCT(CodeObservers::Cleanup()); if (FLAG_support_timeline) { if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down timeline\n", diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index 1c4c4f59986..3d41c2614c0 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc @@ -479,8 +479,9 @@ ApiLocalScope* Api::TopScope(Thread* thread) { } void Api::InitOnce() { - ASSERT(api_native_key_ == kUnsetThreadLocalKey); - api_native_key_ = OSThread::CreateThreadLocal(); + if (api_native_key_ == kUnsetThreadLocalKey) { + api_native_key_ = OSThread::CreateThreadLocal(); + } ASSERT(api_native_key_ != kUnsetThreadLocalKey); } @@ -511,6 +512,13 @@ void Api::InitHandles() { empty_string_handle_ = InitNewReadOnlyApiHandle(Symbols::Empty().raw()); } +void Api::Cleanup() { + true_handle_ = NULL; + false_handle_ = NULL; + null_handle_ = NULL; + empty_string_handle_ = NULL; +} + bool Api::StringGetPeerHelper(NativeArguments* arguments, int arg_index, void** peer) { diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h index 76747d5757f..6c5c322dfd4 100644 --- a/runtime/vm/dart_api_impl.h +++ b/runtime/vm/dart_api_impl.h @@ -244,6 +244,9 @@ class Api : AllStatic { // Allocates handles for objects in the VM isolate. static void InitHandles(); + // Cleanup + static void Cleanup(); + // Helper function to get the peer value of an external string object. static bool StringGetPeerHelper(NativeArguments* args, int arg_index, diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc index 9b506411386..bf6f3c0b896 100644 --- a/runtime/vm/dart_api_impl_test.cc +++ b/runtime/vm/dart_api_impl_test.cc @@ -4,6 +4,7 @@ #include "vm/dart_api_impl.h" #include "bin/builtin.h" +#include "bin/dartutils.h" #include "include/dart_api.h" #include "include/dart_native_api.h" #include "include/dart_tools_api.h" @@ -12,6 +13,7 @@ #include "platform/utils.h" #include "vm/class_finalizer.h" #include "vm/compiler/jit/compiler.h" +#include "vm/dart.h" #include "vm/dart_api_state.h" #include "vm/debugger_api_impl_test.h" #include "vm/heap/verifier.h" @@ -26,6 +28,35 @@ DECLARE_FLAG(bool, use_dart_frontend); #ifndef PRODUCT +UNIT_TEST_CASE(DartAPI_DartInitializeAfterCleanup) { + Dart_InitializeParams params; + memset(¶ms, 0, sizeof(Dart_InitializeParams)); + params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; + params.vm_snapshot_data = TesterState::vm_snapshot_data; + params.create = TesterState::create_callback; + params.shutdown = TesterState::shutdown_callback; + params.cleanup = TesterState::cleanup_callback; + params.start_kernel_isolate = true; + + // Reinitialize and ensure we can execute Dart code. + EXPECT(Dart_Initialize(¶ms) == NULL); + { + TestIsolateScope scope; + const char* kScriptChars = + "int testMain() {\n" + " return 42;\n" + "}\n"; + Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); + EXPECT_VALID(lib); + Dart_Handle result = Dart_Invoke(lib, NewString("testMain"), 0, NULL); + EXPECT_VALID(result); + int64_t value = 0; + EXPECT_VALID(Dart_IntegerToInt64(result, &value)); + EXPECT_EQ(42, value); + } + EXPECT(Dart_Cleanup() == NULL); +} + TEST_CASE(DartAPI_ErrorHandleBasics) { const char* kScriptChars = "void testMain() {\n" @@ -57,7 +88,6 @@ TEST_CASE(DartAPI_ErrorHandleBasics) { EXPECT(Dart_IsError(Dart_ErrorGetException(instance))); EXPECT(Dart_IsError(Dart_ErrorGetException(error))); EXPECT_VALID(Dart_ErrorGetException(exception)); - EXPECT(Dart_IsError(Dart_ErrorGetStackTrace(instance))); EXPECT(Dart_IsError(Dart_ErrorGetStackTrace(error))); EXPECT_VALID(Dart_ErrorGetStackTrace(exception)); @@ -3539,6 +3569,7 @@ static Dart_Handle LoadScript(const char* url_str, const char* source) { if (error != NULL) { return Dart_NewApiError(error); } + TestCaseBase::AddToKernelBuffers(kernel_buffer); return Dart_LoadScriptFromKernel(kernel_buffer, kernel_buffer_size); } } diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc index b597adb9a68..88792e53bfb 100644 --- a/runtime/vm/debugger_api_impl_test.cc +++ b/runtime/vm/debugger_api_impl_test.cc @@ -268,14 +268,17 @@ DART_EXPORT Dart_Handle Dart_EvaluateStaticExpr(Dart_Handle lib_handle, const uint8_t* kernel_bytes = compilation_result.kernel; intptr_t kernel_length = compilation_result.kernel_size; - return Api::NewHandle(T, lib.EvaluateCompiledExpression( - kernel_bytes, kernel_length, - /* type_definitions= */ - Array::empty_array(), - /* param_values= */ - Array::empty_array(), - /* type_param_values= */ - TypeArguments::null_type_arguments())); + Dart_Handle result = Api::NewHandle( + T, + lib.EvaluateCompiledExpression(kernel_bytes, kernel_length, + /* type_definitions= */ + Array::empty_array(), + /* param_values= */ + Array::empty_array(), + /* type_param_values= */ + TypeArguments::null_type_arguments())); + free(const_cast(kernel_bytes)); + return result; } } diff --git a/runtime/vm/heap/pointer_block.cc b/runtime/vm/heap/pointer_block.cc index 2d0d2a1de58..50443fc29f5 100644 --- a/runtime/vm/heap/pointer_block.cc +++ b/runtime/vm/heap/pointer_block.cc @@ -29,13 +29,15 @@ Mutex* BlockStack::global_mutex_ = NULL; template void BlockStack::InitOnce() { global_empty_ = new List(); - global_mutex_ = new Mutex(); + if (global_mutex_ == NULL) { + global_mutex_ = new Mutex(); + } } template void BlockStack::ShutDown() { delete global_empty_; - delete global_mutex_; + global_empty_ = NULL; } template diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc index b732ff19857..17872dd450a 100644 --- a/runtime/vm/heap/scavenger.cc +++ b/runtime/vm/heap/scavenger.cc @@ -289,12 +289,19 @@ SemiSpace::~SemiSpace() { Mutex* SemiSpace::mutex_ = NULL; SemiSpace* SemiSpace::cache_ = NULL; -void SemiSpace::InitOnce() { - ASSERT(mutex_ == NULL); - mutex_ = new Mutex(); +void SemiSpace::Init() { + if (mutex_ == NULL) { + mutex_ = new Mutex(); + } ASSERT(mutex_ != NULL); } +void SemiSpace::Cleanup() { + MutexLocker locker(mutex_); + delete cache_; + cache_ = NULL; +} + SemiSpace* SemiSpace::New(intptr_t size_in_words, const char* name) { { MutexLocker locker(mutex_); diff --git a/runtime/vm/heap/scavenger.h b/runtime/vm/heap/scavenger.h index 45e0c3cb72a..412395d3fc0 100644 --- a/runtime/vm/heap/scavenger.h +++ b/runtime/vm/heap/scavenger.h @@ -28,7 +28,8 @@ class ScavengerVisitor; // Wrapper around VirtualMemory that adds caching and handles the empty case. class SemiSpace { public: - static void InitOnce(); + static void Init(); + static void Cleanup(); // Get a space of the given size. Returns NULL on out of memory. If size is 0, // returns an empty space: pointer(), start() and end() all return NULL. diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc index 254c654afb0..551311ce5a4 100644 --- a/runtime/vm/isolate.cc +++ b/runtime/vm/isolate.cc @@ -1041,7 +1041,9 @@ Isolate::~Isolate() { void Isolate::InitOnce() { create_callback_ = NULL; - isolates_list_monitor_ = new Monitor(); + if (isolates_list_monitor_ == NULL) { + isolates_list_monitor_ = new Monitor(); + } ASSERT(isolates_list_monitor_ != NULL); EnableIsolateCreation(); } diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc index 1df033400aa..f61e32181f5 100644 --- a/runtime/vm/isolate_reload.cc +++ b/runtime/vm/isolate_reload.cc @@ -639,6 +639,9 @@ void IsolateReloadContext::Reload(bool force_reload, const String& error_str = String::Handle(String::New(retval.error)); free(retval.error); const ApiError& error = ApiError::Handle(ApiError::New(error_str)); + if (retval.kernel != NULL) { + free(const_cast(retval.kernel)); + } AddReasonForCancelling(new Aborted(zone_, error)); ReportReasonsForCancelling(); CommonFinalizeTail(); diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc index 563cb902ba3..7aab969740a 100644 --- a/runtime/vm/isolate_reload_test.cc +++ b/runtime/vm/isolate_reload_test.cc @@ -136,6 +136,7 @@ TEST_CASE(IsolateReload_KernelIncrementalCompile) { lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size); EXPECT_VALID(lib); + free(const_cast(kernel_buffer)); } result = Dart_Invoke(lib, NewString("main"), 0, NULL); result = Dart_IntegerToInt64(result, &value); @@ -197,6 +198,7 @@ TEST_CASE(IsolateReload_KernelIncrementalCompileAppAndLib) { lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size); EXPECT_VALID(lib); + free(const_cast(kernel_buffer)); } result = Dart_Invoke(lib, NewString("main"), 0, NULL); result = Dart_IntegerToInt64(result, &value); @@ -274,6 +276,7 @@ TEST_CASE(IsolateReload_KernelIncrementalCompileGenerics) { lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size); EXPECT_VALID(lib); + free(const_cast(kernel_buffer)); } result = Dart_Invoke(lib, NewString("main"), 0, NULL); result = Dart_IntegerToInt64(result, &value); diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc index 7a132b56005..f0e228df6c8 100644 --- a/runtime/vm/kernel_isolate.cc +++ b/runtime/vm/kernel_isolate.cc @@ -221,6 +221,8 @@ class RunKernelTask : public ThreadPool::Task { }; void KernelIsolate::Run() { + MonitorLocker ml(monitor_); + initializing_ = true; // Grab the isolate create callback here to avoid race conditions with tests // that change this after Dart_Initialize returns. create_callback_ = Isolate::CreateCallback(); diff --git a/runtime/vm/message_handler_test.cc b/runtime/vm/message_handler_test.cc index 75e0077d12f..06771789fa0 100644 --- a/runtime/vm/message_handler_test.cc +++ b/runtime/vm/message_handler_test.cc @@ -40,7 +40,10 @@ class TestMessageHandler : public MessageHandler { end_called_(false), results_(NULL) {} - ~TestMessageHandler() { delete[] port_buffer_; } + ~TestMessageHandler() { + PortMap::ClosePorts(this); + delete[] port_buffer_; + } void MessageNotify(Message::Priority priority) { notify_count_++; } @@ -233,7 +236,6 @@ VM_UNIT_TEST_CASE(MessageHandler_HandleNextMessage) { EXPECT_EQ(port2, ports[0]); EXPECT_EQ(port3, ports[1]); EXPECT_EQ(port1, ports[2]); - PortMap::ClosePorts(&handler); } VM_UNIT_TEST_CASE(MessageHandler_HandleNextMessage_ProcessOOBAfterError) { @@ -394,7 +396,6 @@ VM_UNIT_TEST_CASE(MessageHandler_Run) { } handler_peer.decrement_live_ports(); EXPECT(!handler.HasLivePorts()); - PortMap::ClosePorts(&handler); delete[] ports; } diff --git a/runtime/vm/metrics.cc b/runtime/vm/metrics.cc index 94fd0bf63f4..d2208ac97c3 100644 --- a/runtime/vm/metrics.cc +++ b/runtime/vm/metrics.cc @@ -54,7 +54,7 @@ void Metric::Init(const char* name, const char* description, Unit unit) { RegisterWithVM(); } -Metric::~Metric() { +void Metric::CleanupInstance() { // Only deregister metrics which had been registered. Metrics without a name // are from shallow copy isolates. if (name_ != NULL) { @@ -66,6 +66,10 @@ Metric::~Metric() { } } +Metric::~Metric() { + CleanupInstance(); +} + #ifndef PRODUCT static const char* UnitString(intptr_t unit) { switch (unit) { @@ -321,6 +325,10 @@ void Metric::Cleanup() { } OS::PrintErr("\n"); } +#define VM_METRIC_CLEANUP(type, variable, name, unit) \ + vm_metric_##variable##_.CleanupInstance(); + VM_METRIC_LIST(VM_METRIC_CLEANUP); +#undef VM_METRIC_CLEANUP } MaxMetric::MaxMetric() : Metric() { diff --git a/runtime/vm/metrics.h b/runtime/vm/metrics.h index 530cc4dd7d0..9e58fdfd4d3 100644 --- a/runtime/vm/metrics.h +++ b/runtime/vm/metrics.h @@ -57,6 +57,8 @@ class Metric { // Initialize and register a metric for the VM. void Init(const char* name, const char* description, Unit unit); + void CleanupInstance(); + virtual ~Metric(); #ifndef PRODUCT diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 5a92e029012..8fb731f1286 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -950,6 +950,46 @@ void Object::FinishInitOnce(Isolate* isolate) { void_type_->SetTypeTestingStub(instr); } +void Object::Cleanup() { + null_ = reinterpret_cast(RAW_NULL); + class_class_ = reinterpret_cast(RAW_NULL); + dynamic_class_ = reinterpret_cast(RAW_NULL); + void_class_ = reinterpret_cast(RAW_NULL); + unresolved_class_class_ = reinterpret_cast(RAW_NULL); + type_arguments_class_ = reinterpret_cast(RAW_NULL); + patch_class_class_ = reinterpret_cast(RAW_NULL); + function_class_ = reinterpret_cast(RAW_NULL); + closure_data_class_ = reinterpret_cast(RAW_NULL); + signature_data_class_ = reinterpret_cast(RAW_NULL); + redirection_data_class_ = reinterpret_cast(RAW_NULL); + field_class_ = reinterpret_cast(RAW_NULL); + literal_token_class_ = reinterpret_cast(RAW_NULL); + token_stream_class_ = reinterpret_cast(RAW_NULL); + script_class_ = reinterpret_cast(RAW_NULL); + library_class_ = reinterpret_cast(RAW_NULL); + namespace_class_ = reinterpret_cast(RAW_NULL); + kernel_program_info_class_ = reinterpret_cast(RAW_NULL); + code_class_ = reinterpret_cast(RAW_NULL); + instructions_class_ = reinterpret_cast(RAW_NULL); + object_pool_class_ = reinterpret_cast(RAW_NULL); + pc_descriptors_class_ = reinterpret_cast(RAW_NULL); + code_source_map_class_ = reinterpret_cast(RAW_NULL); + stackmap_class_ = reinterpret_cast(RAW_NULL); + var_descriptors_class_ = reinterpret_cast(RAW_NULL); + exception_handlers_class_ = reinterpret_cast(RAW_NULL); + context_class_ = reinterpret_cast(RAW_NULL); + context_scope_class_ = reinterpret_cast(RAW_NULL); + singletargetcache_class_ = reinterpret_cast(RAW_NULL); + unlinkedcall_class_ = reinterpret_cast(RAW_NULL); + icdata_class_ = reinterpret_cast(RAW_NULL); + megamorphic_cache_class_ = reinterpret_cast(RAW_NULL); + subtypetestcache_class_ = reinterpret_cast(RAW_NULL); + api_error_class_ = reinterpret_cast(RAW_NULL); + language_error_class_ = reinterpret_cast(RAW_NULL); + unhandled_exception_class_ = reinterpret_cast(RAW_NULL); + unwind_error_class_ = reinterpret_cast(RAW_NULL); +} + // An object visitor which will mark all visited objects. This is used to // premark all objects in the vm_isolate_ heap. Also precalculates hash // codes so that we can get the identity hash code of objects in the read- @@ -12482,6 +12522,10 @@ static RawObject* EvaluateCompiledExpressionHelper( kernel::KernelLoader loader(kernel_pgm); const Object& result = Object::Handle( loader.LoadExpressionEvaluationFunction(library_url, klass)); + + delete kernel_pgm; + kernel_pgm = NULL; + if (result.IsError()) return result.raw(); const Function& callee = Function::Cast(result); diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 4aace8f24d0..8025cc826a1 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -465,6 +465,8 @@ class Object { static void FinalizeVMIsolate(Isolate* isolate); static void FinalizeReadOnlyObject(RawObject* object); + static void Cleanup(); + // Initialize a new isolate either from a Kernel IR, from source, or from a // snapshot. static RawError* Init(Isolate* isolate, diff --git a/runtime/vm/os_android.cc b/runtime/vm/os_android.cc index 78e7e45bbd3..8a35d40abb9 100644 --- a/runtime/vm/os_android.cc +++ b/runtime/vm/os_android.cc @@ -357,12 +357,6 @@ void OS::PrintErr(const char* format, ...) { } void OS::InitOnce() { - // TODO(5411554): For now we check that initonce is called only once, - // Once there is more formal mechanism to call InitOnce we can move - // this check there. - static bool init_once_called = false; - ASSERT(init_once_called == false); - init_once_called = true; } void OS::Shutdown() {} diff --git a/runtime/vm/os_fuchsia.cc b/runtime/vm/os_fuchsia.cc index a6b7a18ef79..e03fbcffa14 100644 --- a/runtime/vm/os_fuchsia.cc +++ b/runtime/vm/os_fuchsia.cc @@ -254,12 +254,6 @@ void OS::PrintErr(const char* format, ...) { } void OS::InitOnce() { - // TODO(5411554): For now we check that initonce is called only once, - // Once there is more formal mechanism to call InitOnce we can move - // this check there. - static bool init_once_called = false; - ASSERT(init_once_called == false); - init_once_called = true; auto environment_services = std::make_shared(); auto env_service_root = component::subtle::CreateStaticServiceRootHandle(); environment_services->Bind(std::move(env_service_root)); diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc index 13936fbbb7e..00584947f42 100644 --- a/runtime/vm/os_linux.cc +++ b/runtime/vm/os_linux.cc @@ -655,14 +655,7 @@ void OS::PrintErr(const char* format, ...) { va_end(args); } -void OS::InitOnce() { - // TODO(5411554): For now we check that initonce is called only once, - // Once there is more formal mechanism to call InitOnce we can move - // this check there. - static bool init_once_called = false; - ASSERT(init_once_called == false); - init_once_called = true; -} +void OS::InitOnce() {} void OS::Shutdown() {} diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc index e423c7a311e..62e8cae640b 100644 --- a/runtime/vm/os_macos.cc +++ b/runtime/vm/os_macos.cc @@ -303,13 +303,6 @@ void OS::PrintErr(const char* format, ...) { } void OS::InitOnce() { - // TODO(5411554): For now we check that initonce is called only once, - // Once there is more formal mechanism to call InitOnce we can move - // this check there. - static bool init_once_called = false; - ASSERT(init_once_called == false); - init_once_called = true; - // See https://github.com/dart-lang/sdk/issues/29539 // This is a workaround for a macos bug, we eagerly call localtime_r so that // libnotify is initialized early before any fork happens. diff --git a/runtime/vm/os_thread.cc b/runtime/vm/os_thread.cc index 125dabf6d45..13ef8a4c173 100644 --- a/runtime/vm/os_thread.cc +++ b/runtime/vm/os_thread.cc @@ -138,13 +138,15 @@ static void DeleteThread(void* thread) { void OSThread::InitOnce() { // Allocate the global OSThread lock. - ASSERT(thread_list_lock_ == NULL); - thread_list_lock_ = new Mutex(); + if (thread_list_lock_ == NULL) { + thread_list_lock_ = new Mutex(); + } ASSERT(thread_list_lock_ != NULL); // Create the thread local key. - ASSERT(thread_key_ == kUnsetThreadLocalKey); - thread_key_ = CreateThreadLocal(DeleteThread); + if (thread_key_ == kUnsetThreadLocalKey) { + thread_key_ = CreateThreadLocal(DeleteThread); + } ASSERT(thread_key_ != kUnsetThreadLocalKey); // Enable creation of OSThread structures in the VM. diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc index c9a102b647c..333cb873db3 100644 --- a/runtime/vm/os_win.cc +++ b/runtime/vm/os_win.cc @@ -313,11 +313,10 @@ void OS::PrintErr(const char* format, ...) { } void OS::InitOnce() { - // TODO(5411554): For now we check that initonce is called only once, - // Once there is more formal mechanism to call InitOnce we can move - // this check there. static bool init_once_called = false; - ASSERT(init_once_called == false); + if (init_once_called) { + return; + } init_once_called = true; // Do not pop up a message box when abort is called. _set_abort_behavior(0, _WRITE_ABORT_MSG); diff --git a/runtime/vm/port.cc b/runtime/vm/port.cc index 27ee26d6750..6f41c779a96 100644 --- a/runtime/vm/port.cc +++ b/runtime/vm/port.cc @@ -277,19 +277,42 @@ Isolate* PortMap::GetIsolate(Dart_Port id) { } void PortMap::InitOnce() { - mutex_ = new Mutex(); + if (mutex_ == NULL) { + mutex_ = new Mutex(); + } + ASSERT(mutex_ != NULL); prng_ = new Random(); static const intptr_t kInitialCapacity = 8; // TODO(iposva): Verify whether we want to keep exponentially growing. ASSERT(Utils::IsPowerOfTwo(kInitialCapacity)); - map_ = new Entry[kInitialCapacity]; - memset(map_, 0, kInitialCapacity * sizeof(Entry)); - capacity_ = kInitialCapacity; + if (map_ == NULL) { + // TODO(bkonyi): don't keep map_ after Dart_Cleanup. + map_ = new Entry[kInitialCapacity]; + capacity_ = kInitialCapacity; + } + memset(map_, 0, capacity_ * sizeof(Entry)); used_ = 0; deleted_ = 0; } +void PortMap::Cleanup() { + ASSERT(map_ != NULL); + ASSERT(prng_ != NULL); + for (intptr_t i = 0; i < capacity_; ++i) { + auto handler = map_[i].handler; + if (handler != NULL && handler != deleted_entry_) { + ClosePorts(handler); + delete handler; + } + } + delete prng_; + prng_ = NULL; + // TODO(bkonyi): find out why deleting map_ sometimes causes crashes. + // delete[] map_; + // map_ = NULL; +} + void PortMap::PrintPortsForMessageHandler(MessageHandler* handler, JSONStream* stream) { #ifndef PRODUCT diff --git a/runtime/vm/port.h b/runtime/vm/port.h index 113562e792e..9a05151a1ae 100644 --- a/runtime/vm/port.h +++ b/runtime/vm/port.h @@ -55,6 +55,7 @@ class PortMap : public AllStatic { static Isolate* GetIsolate(Dart_Port id); static void InitOnce(); + static void Cleanup(); static void PrintPortsForMessageHandler(MessageHandler* handler, JSONStream* stream); diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc index d132892d7e6..a48c0e67de2 100644 --- a/runtime/vm/service_test.cc +++ b/runtime/vm/service_test.cc @@ -30,7 +30,10 @@ class ServiceTestMessageHandler : public MessageHandler { public: ServiceTestMessageHandler() : _msg(NULL) {} - ~ServiceTestMessageHandler() { free(_msg); } + ~ServiceTestMessageHandler() { + PortMap::ClosePorts(this); + free(_msg); + } MessageStatus HandleMessage(Message* message) { if (_msg != NULL) { diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc index 472a8257293..2736d9614c7 100644 --- a/runtime/vm/stub_code.cc +++ b/runtime/vm/stub_code.cc @@ -47,6 +47,11 @@ void StubCode::InitOnce() { // Stubs will be loaded from the snapshot. UNREACHABLE(); } + +void StubCode::Cleanup() { + // Stubs will be loaded from the snapshot. + UNREACHABLE(); +} #else #define STUB_CODE_GENERATE(name) \ @@ -61,6 +66,16 @@ void StubCode::InitOnce() { #undef STUB_CODE_GENERATE +#define STUB_CODE_CLEANUP(name) \ + delete entries_[k##name##Index]; \ + entries_[k##name##Index] = NULL; + +void StubCode::Cleanup() { + VM_STUB_CODE_LIST(STUB_CODE_CLEANUP); +} + +#undef STUB_CODE_CLEANUP + RawCode* StubCode::Generate(const char* name, void (*GenerateStub)(Assembler* assembler)) { ObjectPoolWrapper object_pool_wrapper; diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h index 73ff3dd15e4..55dad0be5db 100644 --- a/runtime/vm/stub_code.h +++ b/runtime/vm/stub_code.h @@ -150,6 +150,7 @@ class StubCode : public AllStatic { // only once and the stub code resides in the vm_isolate heap. static void InitOnce(); + static void Cleanup(); static void VisitObjectPointers(ObjectPointerVisitor* visitor); // Returns true if stub code has been initialized. diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc index d57729d0e06..b3ee863647d 100644 --- a/runtime/vm/unit_test.cc +++ b/runtime/vm/unit_test.cc @@ -37,6 +37,11 @@ namespace dart { const uint8_t* platform_strong_dill = kPlatformStrongDill; const intptr_t platform_strong_dill_size = kPlatformStrongDillSize; +const uint8_t* TesterState::vm_snapshot_data = NULL; +Dart_IsolateCreateCallback TesterState::create_callback = NULL; +Dart_IsolateShutdownCallback TesterState::shutdown_callback = NULL; +Dart_IsolateCleanupCallback TesterState::cleanup_callback = NULL; + DEFINE_FLAG(bool, use_dart_frontend, true, @@ -44,8 +49,14 @@ DEFINE_FLAG(bool, DECLARE_FLAG(bool, strong); +void KernelBufferList::AddBufferToList(const uint8_t* kernel_buffer) { + next_ = new KernelBufferList(kernel_buffer_, next_); + kernel_buffer_ = kernel_buffer; +} + TestCaseBase* TestCaseBase::first_ = NULL; TestCaseBase* TestCaseBase::tail_ = NULL; +KernelBufferList* TestCaseBase::current_kernel_buffers_ = NULL; TestCaseBase::TestCaseBase(const char* name) : raw_test_(false), next_(NULL), name_(name) { @@ -62,6 +73,7 @@ void TestCaseBase::RunAllRaw() { while (test != NULL) { if (test->raw_test_) { test->RunTest(); + CleanupState(); } test = test->next_; } @@ -72,11 +84,28 @@ void TestCaseBase::RunAll() { while (test != NULL) { if (!test->raw_test_) { test->RunTest(); + CleanupState(); } test = test->next_; } } +void TestCaseBase::CleanupState() { + if (current_kernel_buffers_ != NULL) { + delete current_kernel_buffers_; + current_kernel_buffers_ = NULL; + } +} + +void TestCaseBase::AddToKernelBuffers(const uint8_t* kernel_buffer) { + ASSERT(kernel_buffer != NULL); + if (current_kernel_buffers_ == NULL) { + current_kernel_buffers_ = new KernelBufferList(kernel_buffer); + } else { + current_kernel_buffers_->AddBufferToList(kernel_buffer); + } +} + Dart_Isolate TestCase::CreateIsolate(const uint8_t* data_buffer, intptr_t len, const uint8_t* instr_buffer, @@ -323,10 +352,18 @@ char* TestCase::ValidateCompilationResult( char* result = OS::SCreate(zone, "Compilation failed %s", compilation_result.error); free(compilation_result.error); + if (compilation_result.kernel != NULL) { + free(const_cast(compilation_result.kernel)); + } + *kernel_buffer = NULL; + *kernel_buffer_size = 0; return result; } *kernel_buffer = compilation_result.kernel; *kernel_buffer_size = compilation_result.kernel_size; + if (compilation_result.error != NULL) { + free(compilation_result.error); + } if (kernel_buffer == NULL) { return OS::SCreate(zone, "front end generated a NULL kernel file"); } @@ -525,6 +562,9 @@ Dart_Handle TestCase::LoadTestLibrary(const char* lib_uri, Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size); EXPECT_VALID(lib); + // Ensure kernel buffer isn't leaked after test is run. + AddToKernelBuffers(kernel_buffer); + // TODO(32618): Kernel doesn't correctly represent the root library. lib = Dart_LookupLibrary(Dart_NewStringFromCString(sourcefiles[0].uri)); DART_CHECK_VALID(lib); @@ -567,6 +607,9 @@ Dart_Handle TestCase::LoadTestScriptWithDFE(int sourcefiles_count, Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size); DART_CHECK_VALID(lib); + // Ensure kernel buffer isn't leaked after test is run. + AddToKernelBuffers(kernel_buffer); + // BOGUS: Kernel doesn't correctly represent the root library. lib = Dart_LookupLibrary(Dart_NewStringFromCString( entry_script_uri != NULL ? entry_script_uri : sourcefiles[0].uri)); @@ -658,6 +701,9 @@ Dart_Handle TestCase::ReloadTestScript(const char* script) { if (compilation_result.status != Dart_KernelCompilationStatus_Ok) { Dart_Handle result = Dart_NewApiError(compilation_result.error); free(compilation_result.error); + if (compilation_result.kernel != NULL) { + free(const_cast(compilation_result.kernel)); + } return result; } } else { diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h index ecdf353d015..ca4239e2226 100644 --- a/runtime/vm/unit_test.h +++ b/runtime/vm/unit_test.h @@ -277,6 +277,36 @@ extern const uint8_t* platform_strong_dill; extern const intptr_t platform_dill_size; extern const intptr_t platform_strong_dill_size; +class TesterState : public AllStatic { + public: + static const uint8_t* vm_snapshot_data; + static Dart_IsolateCreateCallback create_callback; + static Dart_IsolateShutdownCallback shutdown_callback; + static Dart_IsolateCleanupCallback cleanup_callback; +}; + +class KernelBufferList { + public: + explicit KernelBufferList(const uint8_t* kernel_buffer) + : kernel_buffer_(kernel_buffer), next_(NULL) {} + + KernelBufferList(const uint8_t* kernel_buffer, KernelBufferList* next) + : kernel_buffer_(kernel_buffer), next_(next) {} + + ~KernelBufferList() { + free(const_cast(kernel_buffer_)); + if (next_ != NULL) { + delete next_; + } + } + + void AddBufferToList(const uint8_t* kernel_buffer); + + private: + const uint8_t* kernel_buffer_; + KernelBufferList* next_; +}; + class TestCaseBase { public: explicit TestCaseBase(const char* name); @@ -289,8 +319,11 @@ class TestCaseBase { static void RunAll(); static void RunAllRaw(); + static void CleanupState(); + static void AddToKernelBuffers(const uint8_t* kernel_buffer); protected: + static KernelBufferList* current_kernel_buffers_; bool raw_test_; private: