[VM] Dart_Initialize no longer crashes after Dart_Cleanup
Change-Id: I3cfdab9553aad045f024b6f9aec0b40b08234007
Reviewed-on: https://dart-review.googlesource.com/75786
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index b7616aa..89a5add 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -150,8 +150,15 @@
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 @@
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 @@
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 6730986..e769aa1 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -139,10 +139,6 @@
dart/data_uri_import_test/utf16: Crash
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
@@ -219,8 +215,6 @@
cc/Profiler_FunctionTicks: Fail, Pass
cc/Profiler_ToggleRecordAllocation: Fail, Pass
cc/Profiler_TrivialRecordAllocation: Fail, Pass
-cc/Service_Address: Fail
-cc/Service_Code: Fail
[ ($compiler == dartk || $compiler == dartkb) && $checked ]
dart/redirection_type_shuffling_test/00: Pass # Works in --checked mode but not in --strong mode.
diff --git a/runtime/vm/code_observers.cc b/runtime/vm/code_observers.cc
index d8a9de9..c1d982a 100644
--- a/runtime/vm/code_observers.cc
+++ b/runtime/vm/code_observers.cc
@@ -47,7 +47,7 @@
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::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 f789675..f0d856b 100644
--- a/runtime/vm/code_observers.h
+++ b/runtime/vm/code_observers.h
@@ -68,7 +68,7 @@
// 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 8eb3586..ae91b3e 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -195,6 +195,7 @@
val = Instance::Cast(obj).EvaluateCompiledExpression(
receiver_cls, kernel_bytes, kernel_length, Array::empty_array(),
Array::empty_array(), TypeArguments::null_type_arguments());
+ free(const_cast<uint8_t*>(kernel_bytes));
}
EXPECT(!val.IsNull());
EXPECT(!val.IsError());
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index dcc1ac8..a34ee6c 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -176,7 +176,7 @@
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 @@
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 @@
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 @@
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 @@
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 7a079a0..25b834d 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -479,8 +479,9 @@
}
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 @@
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 76747d5..6c5c322 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -244,6 +244,9 @@
// 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 9b50641..bf6f3c0 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 @@
#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 @@
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 @@
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 b597adb..88792e5 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -268,14 +268,17 @@
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<uint8_t*>(kernel_bytes));
+ return result;
}
}
diff --git a/runtime/vm/heap/pointer_block.cc b/runtime/vm/heap/pointer_block.cc
index 2d0d2a1..50443fc 100644
--- a/runtime/vm/heap/pointer_block.cc
+++ b/runtime/vm/heap/pointer_block.cc
@@ -29,13 +29,15 @@
template <int BlockSize>
void BlockStack<BlockSize>::InitOnce() {
global_empty_ = new List();
- global_mutex_ = new Mutex();
+ if (global_mutex_ == NULL) {
+ global_mutex_ = new Mutex();
+ }
}
template <int BlockSize>
void BlockStack<BlockSize>::ShutDown() {
delete global_empty_;
- delete global_mutex_;
+ global_empty_ = NULL;
}
template <int BlockSize>
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index b732ff1..17872dd 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -289,12 +289,19 @@
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 45e0c3c..412395d 100644
--- a/runtime/vm/heap/scavenger.h
+++ b/runtime/vm/heap/scavenger.h
@@ -28,7 +28,8 @@
// 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 d26ed2e..50e1b56 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1041,7 +1041,9 @@
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 4b784f1..9cb1c82 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -629,6 +629,9 @@
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<uint8_t*>(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 2b0594e..2d1f254 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -136,6 +136,7 @@
lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
EXPECT_VALID(lib);
+ free(const_cast<uint8_t*>(kernel_buffer));
}
result = Dart_Invoke(lib, NewString("main"), 0, NULL);
result = Dart_IntegerToInt64(result, &value);
@@ -197,6 +198,7 @@
lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
EXPECT_VALID(lib);
+ free(const_cast<uint8_t*>(kernel_buffer));
}
result = Dart_Invoke(lib, NewString("main"), 0, NULL);
result = Dart_IntegerToInt64(result, &value);
@@ -274,6 +276,7 @@
lib = TestCase::ReloadTestKernel(kernel_buffer, kernel_buffer_size);
EXPECT_VALID(lib);
+ free(const_cast<uint8_t*>(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 7a132b5..f0e228d 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -221,6 +221,8 @@
};
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 75e0077..0677178 100644
--- a/runtime/vm/message_handler_test.cc
+++ b/runtime/vm/message_handler_test.cc
@@ -40,7 +40,10 @@
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 @@
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 @@
}
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 94fd0bf..d2208ac 100644
--- a/runtime/vm/metrics.cc
+++ b/runtime/vm/metrics.cc
@@ -54,7 +54,7 @@
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() {
+ CleanupInstance();
+}
+
#ifndef PRODUCT
static const char* UnitString(intptr_t unit) {
switch (unit) {
@@ -321,6 +325,10 @@
}
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 530cc4d..9e58fdf 100644
--- a/runtime/vm/metrics.h
+++ b/runtime/vm/metrics.h
@@ -57,6 +57,8 @@
// 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 1f464d2..a569a49 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -950,6 +950,46 @@
void_type_->SetTypeTestingStub(instr);
}
+void Object::Cleanup() {
+ null_ = reinterpret_cast<RawObject*>(RAW_NULL);
+ class_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ dynamic_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ void_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ unresolved_class_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ type_arguments_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ patch_class_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ function_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ closure_data_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ signature_data_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ redirection_data_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ field_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ literal_token_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ token_stream_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ script_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ library_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ namespace_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ kernel_program_info_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ code_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ instructions_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ object_pool_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ pc_descriptors_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ code_source_map_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ stackmap_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ var_descriptors_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ exception_handlers_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ context_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ context_scope_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ singletargetcache_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ unlinkedcall_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ icdata_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ megamorphic_cache_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ subtypetestcache_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ api_error_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ language_error_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ unhandled_exception_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+ unwind_error_class_ = reinterpret_cast<RawClass*>(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-
@@ -12481,6 +12521,10 @@
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 608c670..e27aa96 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -465,6 +465,8 @@
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 78e7e45..8a35d40 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -357,12 +357,6 @@
}
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 a6b7a18..e03fbcf 100644
--- a/runtime/vm/os_fuchsia.cc
+++ b/runtime/vm/os_fuchsia.cc
@@ -254,12 +254,6 @@
}
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<component::Services>();
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 13936fb..0058494 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -655,14 +655,7 @@
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 e423c7a..62e8cae 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -303,13 +303,6 @@
}
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 125dabf..13ef8a4 100644
--- a/runtime/vm/os_thread.cc
+++ b/runtime/vm/os_thread.cc
@@ -138,13 +138,15 @@
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 c9a102b..333cb87 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -313,11 +313,10 @@
}
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 27ee26d..d594596 100644
--- a/runtime/vm/port.cc
+++ b/runtime/vm/port.cc
@@ -277,7 +277,10 @@
}
void PortMap::InitOnce() {
- mutex_ = new Mutex();
+ if (mutex_ == NULL) {
+ mutex_ = new Mutex();
+ }
+ ASSERT(mutex_ != NULL);
prng_ = new Random();
static const intptr_t kInitialCapacity = 8;
@@ -290,6 +293,22 @@
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;
+ 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 113562e..9a05151 100644
--- a/runtime/vm/port.h
+++ b/runtime/vm/port.h
@@ -55,6 +55,7 @@
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 d132892..a48c0e6 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -30,7 +30,10 @@
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 472a825..2736d96 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -47,6 +47,11 @@
// 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 @@
#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 73ff3dd..55dad0b 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -150,6 +150,7 @@
// 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 dc76612..f262110 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -37,6 +37,11 @@
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 @@
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 @@
while (test != NULL) {
if (test->raw_test_) {
test->RunTest();
+ CleanupState();
}
test = test->next_;
}
@@ -72,11 +84,28 @@
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,
@@ -322,10 +351,18 @@
char* result =
OS::SCreate(zone, "Compilation failed %s", compilation_result.error);
free(compilation_result.error);
+ if (compilation_result.kernel != NULL) {
+ free(const_cast<uint8_t*>(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");
}
@@ -524,6 +561,9 @@
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);
@@ -566,6 +606,9 @@
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));
@@ -656,12 +699,14 @@
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<uint8_t*>(compilation_result.kernel));
+ }
return result;
}
} else {
SetReloadTestScript(script);
}
-
return TriggerReload();
}
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 1115f6d..2c87b67 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -277,6 +277,36 @@
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<uint8_t*>(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 @@
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: