[vm/sendport] Ensure that partially instantiated static closures keep types when sent over SendPort.

Fixes https://github.com/dart-lang/sdk/issues/43343.

Change-Id: If2a741ba9b13f7817ff765d83f3f5a920860cb9e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/163133
Commit-Queue: Alexander Aprelev <aam@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Alexander Aprelev 2020-09-17 19:17:53 +00:00 committed by commit-bot@chromium.org
parent b5f688e938
commit 26e503612a
5 changed files with 98 additions and 9 deletions

View file

@ -0,0 +1,36 @@
// Copyright (c) 2018, 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.
// Verify that partially instantiated generic function remains instantiated
// after received via ReceivePort.
import 'dart:isolate';
import 'package:expect/expect.dart';
import 'package:async_helper/async_minitest.dart';
// Prevent obfuscation.
@pragma('vm:entry-point')
class Dog {}
// Prevent obfuscation.
@pragma('vm:entry-point')
List<T> decodeFrom<T>(String s) {
return List();
}
// Prevent obfuscation.
@pragma('vm:entry-point')
List<Dog> Function(String s) decodeFromDog = decodeFrom;
void main() async {
final receivePort = ReceivePort();
receivePort.listen(expectAsync1((data) {
print("Received $data");
Expect.equals('$data',
"[Closure: (String) => List<Dog> from Function 'decodeFrom': static.]");
receivePort.close();
}));
print("Sending $decodeFromDog");
receivePort.sendPort.send(<dynamic>[decodeFromDog]);
}

View file

@ -0,0 +1,36 @@
// Copyright (c) 2018, 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.
// Verify that partially instantiated generic function remains instantiated
// after received via ReceivePort.
import 'dart:isolate';
import 'package:expect/expect.dart';
import 'package:async_helper/async_minitest.dart';
// Prevent obfuscation.
@pragma('vm:entry-point')
class Dog {}
// Prevent obfuscation.
@pragma('vm:entry-point')
List<T> decodeFrom<T>(String s) {
return List();
}
// Prevent obfuscation.
@pragma('vm:entry-point')
List<Dog> Function(String s) decodeFromDog = decodeFrom;
void main() async {
final receivePort = ReceivePort();
receivePort.listen(expectAsync1((data) {
print("Received $data");
Expect.equals('$data',
"[Closure: (String) => List<Dog> from Function 'decodeFrom': static.]");
receivePort.close();
}));
print("Sending $decodeFromDog");
receivePort.sendPort.send(<dynamic>[decodeFromDog]);
}

View file

@ -399,8 +399,8 @@ void ClosureLayout::WriteTo(SnapshotWriter* writer,
// Check if closure is serializable, throw an exception otherwise.
FunctionPtr func = writer->IsSerializableClosure(ClosurePtr(this));
if (func != Function::null()) {
writer->WriteStaticImplicitClosure(object_id, func,
writer->GetObjectTags(this));
writer->WriteStaticImplicitClosure(
object_id, func, writer->GetObjectTags(this), delayed_type_arguments_);
return;
}

View file

@ -458,11 +458,25 @@ ObjectPtr SnapshotReader::ReadStaticImplicitClosure(intptr_t object_id,
if (func.IsNull()) {
SetReadException("Invalid function object found in message.");
}
TypeArguments& delayed_type_arguments = TypeArguments::Handle(zone());
delayed_type_arguments ^= ReadObjectImpl(kAsInlinedObject);
func = func.ImplicitClosureFunction();
ASSERT(!func.IsNull());
// Return the associated implicit static closure.
obj = func.ImplicitStaticClosure();
// If delayedtype arguments were provided, create and return new closure with
// those, otherwise return associated implicit static closure.
// Note that static closures can't have instantiator or function types since
// statics can't refer to class type arguments, don't have outer functions.
if (!delayed_type_arguments.IsNull()) {
const Context& context = Context::Handle(zone());
obj = Closure::New(
/*instantiator_type_arguments=*/Object::null_type_arguments(),
/*function_type_arguments=*/Object::null_type_arguments(),
delayed_type_arguments, func, context, Heap::kOld);
} else {
obj = func.ImplicitStaticClosure();
}
return obj.raw();
}
@ -1313,9 +1327,11 @@ void SnapshotWriter::WriteClassId(ClassLayout* cls) {
WriteObjectImpl(cls->name_, kAsInlinedObject);
}
void SnapshotWriter::WriteStaticImplicitClosure(intptr_t object_id,
FunctionPtr func,
intptr_t tags) {
void SnapshotWriter::WriteStaticImplicitClosure(
intptr_t object_id,
FunctionPtr func,
intptr_t tags,
TypeArgumentsPtr delayed_type_arguments) {
// Write out the serialization header value for this object.
WriteInlinedObjectHeader(object_id);
@ -1333,6 +1349,7 @@ void SnapshotWriter::WriteStaticImplicitClosure(intptr_t object_id,
WriteObjectImpl(library->ptr()->url_, kAsInlinedObject);
WriteObjectImpl(cls->ptr()->name_, kAsInlinedObject);
WriteObjectImpl(func->ptr()->name_, kAsInlinedObject);
WriteObjectImpl(delayed_type_arguments, kAsInlinedObject);
}
void SnapshotWriter::ArrayWriteTo(intptr_t object_id,

View file

@ -623,7 +623,8 @@ class SnapshotWriter : public BaseWriter {
void WriteStaticImplicitClosure(intptr_t object_id,
FunctionPtr func,
intptr_t tags);
intptr_t tags,
TypeArgumentsPtr delayed_type_arguments);
protected:
bool CheckAndWritePredefinedObject(ObjectPtr raw);
@ -668,7 +669,6 @@ class SnapshotWriter : public BaseWriter {
friend class ArrayLayout;
friend class ClassLayout;
friend class ClosureDataLayout;
friend class CodeLayout;
friend class ContextScopeLayout;
friend class DynamicLibraryLayout;