From f4e44dd7056905b8de625f21a5f7f32ea1706fa2 Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Tue, 3 Dec 2019 22:00:48 +0000 Subject: [PATCH] [vm] Make kernel buffers live exactly as long as their derived views. When creating a KernelProgramInfo, we create several logical views into the kernel buffer. These are fresh ExternalTypedDatas, rather than proper TypedDataViews, so they do not automically keep the original ExternalTypedData alive. Create an explicit reference to the orginal ExternalTypedData in the KernelProgramInfo. When creating snapshots, this reference is ignored/null'd and the views are turned into copies, effectively dropping the parts of the original buffer that do not have views. Fixes a leak with reload and a use-after-free with eval. Bug: https://github.com/dart-lang/sdk/issues/33973 Bug: https://github.com/dart-lang/sdk/issues/39610 Change-Id: I09d3830133314ccbaa0341d904127c2b6925c4ec Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/126825 Commit-Queue: Ryan Macnak Reviewed-by: Alexander Aprelev Reviewed-by: Martin Kustermann --- .../evaluate_with_escaping_closure_test.dart | 29 ++++++++++++++ runtime/vm/base64.cc | 4 +- runtime/vm/base64.h | 4 +- runtime/vm/base64_test.cc | 9 ++--- runtime/vm/compiler_test.cc | 11 ++--- runtime/vm/debugger.cc | 13 +++--- runtime/vm/debugger.h | 3 +- runtime/vm/debugger_api_impl_test.cc | 10 +++-- runtime/vm/isolate.cc | 10 ----- runtime/vm/isolate.h | 8 ---- runtime/vm/isolate_reload.cc | 28 ++----------- runtime/vm/isolate_reload.h | 2 - runtime/vm/kernel.h | 4 +- runtime/vm/kernel_binary.cc | 1 + runtime/vm/kernel_loader.cc | 2 + runtime/vm/object.cc | 40 ++++++++++++------- runtime/vm/object.h | 12 +++--- runtime/vm/raw_object.h | 3 +- runtime/vm/raw_object_fields.cc | 1 + runtime/vm/service.cc | 19 +++++---- runtime/vm/unit_test.cc | 11 ++--- 21 files changed, 116 insertions(+), 108 deletions(-) create mode 100644 runtime/observatory/tests/service/evaluate_with_escaping_closure_test.dart diff --git a/runtime/observatory/tests/service/evaluate_with_escaping_closure_test.dart b/runtime/observatory/tests/service/evaluate_with_escaping_closure_test.dart new file mode 100644 index 00000000000..bb871307dc6 --- /dev/null +++ b/runtime/observatory/tests/service/evaluate_with_escaping_closure_test.dart @@ -0,0 +1,29 @@ +// Copyright (c) 2019, 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. + +import 'package:observatory/service_io.dart'; +import 'package:unittest/unittest.dart'; +import 'test_helper.dart'; + +dynamic escapedClosure; + +testeeMain() {} + +var tests = [ + (Isolate isolate) async { + Library lib = await isolate.rootLibrary.load(); + + Instance result = await lib.evaluate("escapedClosure = (x, y) => x + y"); + print(result); + expect(result.clazz.name, startsWith('_Closure')); + + for (var i = 0; i < 100; i++) { + result = await lib.evaluate("escapedClosure(3, 4)"); + print(result); + expect(result.valueAsString, equals('7')); + } + }, +]; + +main(args) => runIsolateTests(args, tests, testeeBefore: testeeMain); diff --git a/runtime/vm/base64.cc b/runtime/vm/base64.cc index 60e919d3e57..ec003ae0328 100644 --- a/runtime/vm/base64.cc +++ b/runtime/vm/base64.cc @@ -35,7 +35,7 @@ static const int8_t decode_table[] = { static const char PAD = '='; -uint8_t* DecodeBase64(Zone* zone, const char* str, intptr_t* out_decoded_len) { +uint8_t* DecodeBase64(const char* str, intptr_t* out_decoded_len) { intptr_t len = strlen(str); if (len == 0 || (len % 4 != 0)) { return nullptr; @@ -48,7 +48,7 @@ uint8_t* DecodeBase64(Zone* zone, const char* str, intptr_t* out_decoded_len) { if (current_code_unit == PAD) pad_length++; } intptr_t decoded_en = ((len * 6) >> 3) - pad_length; - uint8_t* bytes = zone->Alloc(decoded_en); + uint8_t* bytes = static_cast(malloc(decoded_en)); for (int i = 0, o = 0; o < decoded_en;) { // Accumulate 4 valid 6 bit Base 64 characters into an int. diff --git a/runtime/vm/base64.h b/runtime/vm/base64.h index 575b61b515f..079850f16d8 100644 --- a/runtime/vm/base64.h +++ b/runtime/vm/base64.h @@ -5,11 +5,11 @@ #ifndef RUNTIME_VM_BASE64_H_ #define RUNTIME_VM_BASE64_H_ -#include "vm/zone.h" +#include "vm/globals.h" namespace dart { -uint8_t* DecodeBase64(Zone* zone, const char* str, intptr_t* out_decoded_len); +uint8_t* DecodeBase64(const char* str, intptr_t* out_decoded_len); } // namespace dart diff --git a/runtime/vm/base64_test.cc b/runtime/vm/base64_test.cc index 406a431b158..cd501ca01c1 100644 --- a/runtime/vm/base64_test.cc +++ b/runtime/vm/base64_test.cc @@ -11,22 +11,21 @@ namespace dart { TEST_CASE(Base64Decode) { intptr_t decoded_len; - uint8_t* decoded_bytes = - DecodeBase64(thread->zone(), "SGVsbG8sIHdvcmxkIQo=", &decoded_len); + uint8_t* decoded_bytes = DecodeBase64("SGVsbG8sIHdvcmxkIQo=", &decoded_len); const char expected_bytes[] = "Hello, world!\n"; intptr_t expected_len = strlen(expected_bytes); EXPECT(!memcmp(expected_bytes, decoded_bytes, expected_len)); EXPECT_EQ(expected_len, decoded_len); + free(decoded_bytes); } TEST_CASE(Base64DecodeMalformed) { intptr_t decoded_len; - EXPECT(DecodeBase64(thread->zone(), "SomethingMalformed", &decoded_len) == - nullptr); + EXPECT(DecodeBase64("SomethingMalformed", &decoded_len) == nullptr); } TEST_CASE(Base64DecodeEmpty) { intptr_t decoded_len; - EXPECT(DecodeBase64(thread->zone(), "", &decoded_len) == nullptr); + EXPECT(DecodeBase64("", &decoded_len) == nullptr); } } // namespace dart diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc index 9155f084b61..2ea85b16f62 100644 --- a/runtime/vm/compiler_test.cc +++ b/runtime/vm/compiler_test.cc @@ -230,13 +230,14 @@ TEST_CASE(EvalExpression) { /* is_static= */ false); EXPECT_EQ(Dart_KernelCompilationStatus_Ok, compilation_result.status); - const uint8_t* kernel_bytes = compilation_result.kernel; - intptr_t kernel_length = compilation_result.kernel_size; + const ExternalTypedData& kernel_buffer = + ExternalTypedData::Handle(ExternalTypedData::NewFinalizeWithFree( + const_cast(compilation_result.kernel), + compilation_result.kernel_size)); 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)); + receiver_cls, kernel_buffer, Array::empty_array(), Array::empty_array(), + TypeArguments::null_type_arguments()); } EXPECT(!val.IsNull()); EXPECT(!val.IsError()); diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc index c5ce88af5d9..2efdac300b5 100644 --- a/runtime/vm/debugger.cc +++ b/runtime/vm/debugger.cc @@ -1463,16 +1463,14 @@ static bool IsPrivateVariableName(const String& var_name) { } RawObject* ActivationFrame::EvaluateCompiledExpression( - const uint8_t* kernel_bytes, - intptr_t kernel_length, + const ExternalTypedData& kernel_buffer, const Array& type_definitions, const Array& arguments, const TypeArguments& type_arguments) { if (function().is_static()) { const Class& cls = Class::Handle(function().Owner()); - return cls.EvaluateCompiledExpression(kernel_bytes, kernel_length, - type_definitions, arguments, - type_arguments); + return cls.EvaluateCompiledExpression(kernel_buffer, type_definitions, + arguments, type_arguments); } else { const Object& receiver = Object::Handle(GetReceiver()); const Class& method_cls = Class::Handle(function().origin()); @@ -1481,9 +1479,8 @@ RawObject* ActivationFrame::EvaluateCompiledExpression( return Object::null(); } const Instance& inst = Instance::Cast(receiver); - return inst.EvaluateCompiledExpression(method_cls, kernel_bytes, - kernel_length, type_definitions, - arguments, type_arguments); + return inst.EvaluateCompiledExpression( + method_cls, kernel_buffer, type_definitions, arguments, type_arguments); } } diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h index b1fdd4019f0..390b124aa49 100644 --- a/runtime/vm/debugger.h +++ b/runtime/vm/debugger.h @@ -353,8 +353,7 @@ class ActivationFrame : public ZoneAllocated { const GrowableObjectArray& param_values, const GrowableObjectArray& type_params_names); - RawObject* EvaluateCompiledExpression(const uint8_t* kernel_bytes, - intptr_t kernel_length, + RawObject* EvaluateCompiledExpression(const ExternalTypedData& kernel_data, const Array& arguments, const Array& type_definitions, const TypeArguments& type_arguments); diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc index ddcbb7cfa52..8ca5a6792f4 100644 --- a/runtime/vm/debugger_api_impl_test.cc +++ b/runtime/vm/debugger_api_impl_test.cc @@ -190,18 +190,20 @@ DART_EXPORT Dart_Handle Dart_EvaluateStaticExpr(Dart_Handle lib_handle, return Api::NewError("Failed to compile expression."); } - const uint8_t* kernel_bytes = compilation_result.kernel; - intptr_t kernel_length = compilation_result.kernel_size; + const ExternalTypedData& kernel_buffer = + ExternalTypedData::Handle(ExternalTypedData::NewFinalizeWithFree( + const_cast(compilation_result.kernel), + compilation_result.kernel_size)); + Dart_Handle result = Api::NewHandle( T, - lib.EvaluateCompiledExpression(kernel_bytes, kernel_length, + lib.EvaluateCompiledExpression(kernel_buffer, /* 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/isolate.cc b/runtime/vm/isolate.cc index 0655dc88917..a7dda01bf02 100644 --- a/runtime/vm/isolate.cc +++ b/runtime/vm/isolate.cc @@ -1258,7 +1258,6 @@ Isolate::Isolate(IsolateGroup* isolate_group, tag_table_(GrowableObjectArray::null()), deoptimized_code_array_(GrowableObjectArray::null()), sticky_error_(Error::null()), - reloaded_kernel_blobs_(GrowableObjectArray::null()), field_list_mutex_(NOT_IN_PRODUCT("Isolate::field_list_mutex_")), boxed_field_list_(GrowableObjectArray::null()), spawn_count_monitor_(), @@ -1489,14 +1488,6 @@ Isolate* Isolate::InitIsolate(const char* name_prefix, return result; } -void Isolate::RetainKernelBlob(const ExternalTypedData& kernel_blob) { - if (reloaded_kernel_blobs_ == Object::null()) { - reloaded_kernel_blobs_ = GrowableObjectArray::New(); - } - auto& kernel_blobs = GrowableObjectArray::Handle(reloaded_kernel_blobs_); - kernel_blobs.Add(kernel_blob); -} - Thread* Isolate::mutator_thread() const { ASSERT(thread_registry() != nullptr); return mutator_thread_; @@ -2330,7 +2321,6 @@ void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor, visitor->VisitPointer( reinterpret_cast(&deoptimized_code_array_)); visitor->VisitPointer(reinterpret_cast(&sticky_error_)); - visitor->VisitPointer(reinterpret_cast(&reloaded_kernel_blobs_)); #if !defined(PRODUCT) visitor->VisitPointer( reinterpret_cast(&pending_service_extension_calls_)); diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h index b5913f83352..c8cf0251f79 100644 --- a/runtime/vm/isolate.h +++ b/runtime/vm/isolate.h @@ -868,8 +868,6 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry { RawError* sticky_error() const { return sticky_error_; } DART_WARN_UNUSED_RESULT RawError* StealStickyError(); - void RetainKernelBlob(const ExternalTypedData& kernel_blob); - bool compilation_allowed() const { return CompilationAllowedBit::decode(isolate_flags_); } @@ -1269,12 +1267,6 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry { RawError* sticky_error_; - // Issue(dartbug.com/33973): We keep a reference to [ExternalTypedData]s with - // finalizers to ensure we keep the hot-reloaded kernel blobs alive. - // - // -> We should get rid of this field once Issue 33973 is fixed. - RawGrowableObjectArray* reloaded_kernel_blobs_; - // Isolate list next pointer. Isolate* next_ = nullptr; diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc index 7cb3ca60825..c93c2632c64 100644 --- a/runtime/vm/isolate_reload.cc +++ b/runtime/vm/isolate_reload.cc @@ -597,7 +597,9 @@ bool IsolateGroupReloadContext::Reload(bool force_reload, } } const auto& typed_data = ExternalTypedData::Handle( - Z, MakeRetainedTypedData(kernel_buffer, kernel_buffer_size)); + Z, ExternalTypedData::NewFinalizeWithFree( + const_cast(kernel_buffer), kernel_buffer_size)); + kernel_program = kernel::Program::ReadFromTypedData(typed_data); } @@ -936,30 +938,6 @@ char* IsolateGroupReloadContext::CompileToKernel(bool force_reload, return nullptr; } -RawExternalTypedData* IsolateGroupReloadContext::MakeRetainedTypedData( - const uint8_t* kernel_buffer, - intptr_t kernel_buffer_size) { - // The ownership of the kernel buffer goes now to the VM. - const auto& typed_data = ExternalTypedData::Handle( - Z, ExternalTypedData::New(kExternalTypedDataUint8ArrayCid, - const_cast(kernel_buffer), - kernel_buffer_size, Heap::kOld)); - typed_data.AddFinalizer( - const_cast(kernel_buffer), - [](void* isolate_callback_data, Dart_WeakPersistentHandle handle, - void* data) { free(data); }, - kernel_buffer_size); - - // TODO(dartbug.com/33973): Change the heap objects to have a proper - // retaining path to the kernel blob and ensure the finalizer will free it - // once there are no longer references to it. - // (The [ExternalTypedData] currently referenced by e.g. functions point - // into the middle of c-allocated buffer and don't have a finalizer). - first_isolate_->RetainKernelBlob(typed_data); - - return typed_data.raw(); -} - void IsolateReloadContext::ReloadPhase1AllocateStorageMapsAndCheckpoint() { // Preallocate storage for maps. old_classes_set_storage_ = diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h index bd3f86d44be..ba6ba598b0a 100644 --- a/runtime/vm/isolate_reload.h +++ b/runtime/vm/isolate_reload.h @@ -216,8 +216,6 @@ class IsolateGroupReloadContext { const char* packages_url, const uint8_t** kernel_buffer, intptr_t* kernel_buffer_size); - RawExternalTypedData* MakeRetainedTypedData(const uint8_t* kernel_buffer, - intptr_t kernel_buffer_size); void FindModifiedSources(bool force_reload, Dart_SourceFile** modified_sources, intptr_t* count, diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h index 9afdc32c3f4..43babb89751 100644 --- a/runtime/vm/kernel.h +++ b/runtime/vm/kernel.h @@ -88,12 +88,13 @@ class Program { return metadata_mappings_offset_; } intptr_t constant_table_offset() { return constant_table_offset_; } + const ExternalTypedData* typed_data() { return typed_data_; } const uint8_t* kernel_data() { return kernel_data_; } intptr_t kernel_data_size() { return kernel_data_size_; } intptr_t library_count() { return library_count_; } private: - Program() : kernel_data_(NULL), kernel_data_size_(-1) {} + Program() : typed_data_(NULL), kernel_data_(NULL), kernel_data_size_(-1) {} bool single_program_; uint32_t binary_version_; @@ -118,6 +119,7 @@ class Program { // The offset from the start of the binary to the start of the string table. intptr_t string_table_offset_; + const ExternalTypedData* typed_data_; const uint8_t* kernel_data_; intptr_t kernel_data_size_; diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc index 50e5e42d110..c1103d1adc5 100644 --- a/runtime/vm/kernel_binary.cc +++ b/runtime/vm/kernel_binary.cc @@ -124,6 +124,7 @@ std::unique_ptr Program::ReadFrom(Reader* reader, const char** error) { std::unique_ptr program(new Program()); program->binary_version_ = formatVersion; + program->typed_data_ = reader->typed_data(); program->kernel_data_ = reader->buffer(); program->kernel_data_size_ = reader->size(); diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc index 343dcb1e5f8..22089d6f162 100644 --- a/runtime/vm/kernel_loader.cc +++ b/runtime/vm/kernel_loader.cc @@ -418,6 +418,8 @@ void KernelLoader::InitializeFields(UriToSourceTable* uri_to_source_table) { kernel_program_info_ = KernelProgramInfo::New( offsets, data, names, metadata_payloads, metadata_mappings, constants_table, scripts, libraries_cache, classes_cache, + program_->typed_data() == nullptr ? Object::null_object() + : *program_->typed_data(), program_->binary_version()); H.InitFromKernelProgramInfo(kernel_program_info_); diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 5d6ae8f8d7e..30804a6ac3a 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -3698,8 +3698,7 @@ RawObject* Class::Invoke(const String& function_name, } static RawObject* EvaluateCompiledExpressionHelper( - const uint8_t* kernel_bytes, - intptr_t kernel_length, + const ExternalTypedData& kernel_buffer, const Array& type_definitions, const String& library_url, const String& klass, @@ -3707,8 +3706,7 @@ static RawObject* EvaluateCompiledExpressionHelper( const TypeArguments& type_arguments); RawObject* Class::EvaluateCompiledExpression( - const uint8_t* kernel_bytes, - intptr_t kernel_length, + const ExternalTypedData& kernel_buffer, const Array& type_definitions, const Array& arguments, const TypeArguments& type_arguments) const { @@ -3721,7 +3719,7 @@ RawObject* Class::EvaluateCompiledExpression( } return EvaluateCompiledExpressionHelper( - kernel_bytes, kernel_length, type_definitions, + kernel_buffer, type_definitions, String::Handle(Library::Handle(library()).url()), IsTopLevel() ? String::Handle() : String::Handle(UserVisibleName()), arguments, type_arguments); @@ -11538,14 +11536,13 @@ RawObject* Library::Invoke(const String& function_name, } RawObject* Library::EvaluateCompiledExpression( - const uint8_t* kernel_bytes, - intptr_t kernel_length, + const ExternalTypedData& kernel_buffer, const Array& type_definitions, const Array& arguments, const TypeArguments& type_arguments) const { return EvaluateCompiledExpressionHelper( - kernel_bytes, kernel_length, type_definitions, String::Handle(url()), - String::Handle(), arguments, type_arguments); + kernel_buffer, type_definitions, String::Handle(url()), String::Handle(), + arguments, type_arguments); } void Library::InitNativeWrappersLibrary(Isolate* isolate, bool is_kernel) { @@ -11603,8 +11600,7 @@ class LibraryLookupTraits { typedef UnorderedHashMap LibraryLookupMap; static RawObject* EvaluateCompiledExpressionHelper( - const uint8_t* kernel_bytes, - intptr_t kernel_length, + const ExternalTypedData& kernel_buffer, const Array& type_definitions, const String& library_url, const String& klass, @@ -11618,7 +11614,7 @@ static RawObject* EvaluateCompiledExpressionHelper( return ApiError::New(error_str); #else std::unique_ptr kernel_pgm = - kernel::Program::ReadFromBuffer(kernel_bytes, kernel_length); + kernel::Program::ReadFromTypedData(kernel_buffer); if (kernel_pgm == NULL) { return ApiError::New(String::Handle( @@ -12186,6 +12182,7 @@ RawKernelProgramInfo* KernelProgramInfo::New( const Array& scripts, const Array& libraries_cache, const Array& classes_cache, + const Object& retained_kernel_blob, const uint32_t binary_version) { const KernelProgramInfo& info = KernelProgramInfo::Handle(KernelProgramInfo::New()); @@ -12200,6 +12197,8 @@ RawKernelProgramInfo* KernelProgramInfo::New( info.StorePointer(&info.raw_ptr()->constants_table_, constants_table.raw()); info.StorePointer(&info.raw_ptr()->libraries_cache_, libraries_cache.raw()); info.StorePointer(&info.raw_ptr()->classes_cache_, classes_cache.raw()); + info.StorePointer(&info.raw_ptr()->retained_kernel_blob_, + retained_kernel_blob.raw()); info.set_kernel_binary_version(binary_version); return info.raw(); } @@ -16473,8 +16472,7 @@ RawObject* Instance::Invoke(const String& function_name, RawObject* Instance::EvaluateCompiledExpression( const Class& method_cls, - const uint8_t* kernel_bytes, - intptr_t kernel_length, + const ExternalTypedData& kernel_buffer, const Array& type_definitions, const Array& arguments, const TypeArguments& type_arguments) const { @@ -16488,7 +16486,7 @@ RawObject* Instance::EvaluateCompiledExpression( } return EvaluateCompiledExpressionHelper( - kernel_bytes, kernel_length, type_definitions, + kernel_buffer, type_definitions, String::Handle(Library::Handle(method_cls.library()).url()), String::Handle(method_cls.UserVisibleName()), arguments_with_receiver, type_arguments); @@ -21686,6 +21684,18 @@ RawExternalTypedData* ExternalTypedData::New(intptr_t class_id, return result.raw(); } +RawExternalTypedData* ExternalTypedData::NewFinalizeWithFree(uint8_t* data, + intptr_t len) { + ExternalTypedData& result = ExternalTypedData::Handle(ExternalTypedData::New( + kExternalTypedDataUint8ArrayCid, data, len, Heap::kOld)); + result.AddFinalizer( + data, + [](void* isolate_callback_data, Dart_WeakPersistentHandle handle, + void* data) { free(data); }, + len); + return result.raw(); +} + RawTypedDataView* TypedDataView::New(intptr_t class_id, Heap::Space space) { auto& result = TypedDataView::Handle(); { diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 4bd6f50f4a8..402e025e54d 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -1374,8 +1374,7 @@ class Class : public Object { // (type_)param_names, and is invoked with the (type)argument values given in // (type_)param_values. RawObject* EvaluateCompiledExpression( - const uint8_t* kernel_bytes, - intptr_t kernel_length, + const ExternalTypedData& kernel_buffer, const Array& type_definitions, const Array& param_values, const TypeArguments& type_param_values) const; @@ -4154,8 +4153,7 @@ class Library : public Object { // parameters given in (type_)param_names, and is invoked with the (type) // argument values given in (type_)param_values. RawObject* EvaluateCompiledExpression( - const uint8_t* kernel_bytes, - intptr_t kernel_length, + const ExternalTypedData& kernel_buffer, const Array& type_definitions, const Array& param_values, const TypeArguments& type_param_values) const; @@ -4581,6 +4579,7 @@ class KernelProgramInfo : public Object { const Array& scripts, const Array& libraries_cache, const Array& classes_cache, + const Object& retained_kernel_blob, const uint32_t binary_version); static intptr_t InstanceSize() { @@ -6553,8 +6552,7 @@ class Instance : public Object { // argument values given in (type_)param_values. RawObject* EvaluateCompiledExpression( const Class& method_cls, - const uint8_t* kernel_bytes, - intptr_t kernel_length, + const ExternalTypedData& kernel_buffer, const Array& type_definitions, const Array& param_values, const TypeArguments& type_param_values) const; @@ -9232,6 +9230,8 @@ class ExternalTypedData : public TypedDataBase { intptr_t len, Heap::Space space = Heap::kNew); + static RawExternalTypedData* NewFinalizeWithFree(uint8_t* data, intptr_t len); + static bool IsExternalTypedData(const Instance& obj) { ASSERT(!obj.IsNull()); intptr_t cid = obj.raw()->GetClassId(); diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 23d384ae305..2a0f479a968 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -1287,7 +1287,8 @@ class RawKernelProgramInfo : public RawObject { RawExternalTypedData* constants_table_; RawArray* libraries_cache_; RawArray* classes_cache_; - VISIT_TO(RawObject*, classes_cache_); + RawObject* retained_kernel_blob_; + VISIT_TO(RawObject*, retained_kernel_blob_); uint32_t kernel_binary_version_; diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc index 079cbe71741..c46b0868e2e 100644 --- a/runtime/vm/raw_object_fields.cc +++ b/runtime/vm/raw_object_fields.cc @@ -93,6 +93,7 @@ namespace dart { F(KernelProgramInfo, constants_table_) \ F(KernelProgramInfo, libraries_cache_) \ F(KernelProgramInfo, classes_cache_) \ + F(KernelProgramInfo, retained_kernel_blob_) \ F(Code, object_pool_) \ F(Code, instructions_) \ F(Code, owner_) \ diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc index a90b073726d..02c49f9cf7f 100644 --- a/runtime/vm/service.cc +++ b/runtime/vm/service.cc @@ -2870,6 +2870,12 @@ static const MethodParameter* evaluate_compiled_expression_params[] = { NULL, }; +RawExternalTypedData* DecodeKernelBuffer(const char* kernel_buffer_base64) { + intptr_t kernel_length; + uint8_t* kernel_buffer = DecodeBase64(kernel_buffer_base64, &kernel_length); + return ExternalTypedData::NewFinalizeWithFree(kernel_buffer, kernel_length); +} + static bool EvaluateCompiledExpression(Thread* thread, JSONStream* js) { if (CheckDebuggerDisabled(thread, js)) { return true; @@ -2898,9 +2904,8 @@ static bool EvaluateCompiledExpression(Thread* thread, JSONStream* js) { const GrowableObjectArray& type_params_names = GrowableObjectArray::Handle(zone, GrowableObjectArray::New()); - intptr_t kernel_length; - const char* kernel_bytes_str = js->LookupParam("kernelBytes"); - uint8_t* kernel_bytes = DecodeBase64(zone, kernel_bytes_str, &kernel_length); + const ExternalTypedData& kernel_data = ExternalTypedData::Handle( + zone, DecodeKernelBuffer(js->LookupParam("kernelBytes"))); if (js->HasParam("frameIndex")) { DebuggerStackTrace* stack = isolate->debugger()->StackTrace(); @@ -2918,7 +2923,7 @@ static bool EvaluateCompiledExpression(Thread* thread, JSONStream* js) { const Object& result = Object::Handle( zone, frame->EvaluateCompiledExpression( - kernel_bytes, kernel_length, + kernel_data, Array::Handle(zone, Array::MakeFixedLength(type_params_names)), Array::Handle(zone, Array::MakeFixedLength(param_values)), type_arguments)); @@ -2951,7 +2956,7 @@ static bool EvaluateCompiledExpression(Thread* thread, JSONStream* js) { const Object& result = Object::Handle( zone, lib.EvaluateCompiledExpression( - kernel_bytes, kernel_length, + kernel_data, Array::Handle(zone, Array::MakeFixedLength(type_params_names)), Array::Handle(zone, Array::MakeFixedLength(param_values)), type_arguments)); @@ -2963,7 +2968,7 @@ static bool EvaluateCompiledExpression(Thread* thread, JSONStream* js) { const Object& result = Object::Handle( zone, cls.EvaluateCompiledExpression( - kernel_bytes, kernel_length, + kernel_data, Array::Handle(zone, Array::MakeFixedLength(type_params_names)), Array::Handle(zone, Array::MakeFixedLength(param_values)), type_arguments)); @@ -2978,7 +2983,7 @@ static bool EvaluateCompiledExpression(Thread* thread, JSONStream* js) { const Object& result = Object::Handle( zone, instance.EvaluateCompiledExpression( - receiver_cls, kernel_bytes, kernel_length, + receiver_cls, kernel_data, Array::Handle(zone, Array::MakeFixedLength(type_params_names)), Array::Handle(zone, Array::MakeFixedLength(param_values)), type_arguments)); diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc index e6b60bb98a8..a6b01615998 100644 --- a/runtime/vm/unit_test.cc +++ b/runtime/vm/unit_test.cc @@ -700,13 +700,14 @@ Dart_Handle TestCase::EvaluateExpression(const Library& lib, return Api::NewError("%s", compilation_result.error); } - const uint8_t* kernel_bytes = compilation_result.kernel; - intptr_t kernel_length = compilation_result.kernel_size; + const ExternalTypedData& kernel_buffer = + ExternalTypedData::Handle(ExternalTypedData::NewFinalizeWithFree( + const_cast(compilation_result.kernel), + compilation_result.kernel_size)); - val = lib.EvaluateCompiledExpression(kernel_bytes, kernel_length, - Array::empty_array(), param_values, + val = lib.EvaluateCompiledExpression(kernel_buffer, Array::empty_array(), + param_values, TypeArguments::null_type_arguments()); - free(const_cast(kernel_bytes)); } return Api::NewHandle(thread, val.raw()); }