mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:36:59 +00:00
Fix for issue 20992 - Allow sending static/top-level functions to other isolates which are spawned using the 'spawn function' functionality.
R=regis@google.com Review URL: https://codereview.chromium.org//982723002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@44297 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
b2d9992127
commit
cfb2df1020
|
@ -6084,6 +6084,21 @@ bool Function::IsImplicitClosureFunction() const {
|
|||
}
|
||||
|
||||
|
||||
bool Function::IsImplicitStaticClosureFunction(RawFunction* func) {
|
||||
NoGCScope no_gc;
|
||||
uint32_t kind_tag = func->ptr()->kind_tag_;
|
||||
if (KindBits::decode(kind_tag) != RawFunction::kClosureFunction) {
|
||||
return false;
|
||||
}
|
||||
if (!StaticBit::decode(kind_tag)) {
|
||||
return false;
|
||||
}
|
||||
RawClosureData* data = reinterpret_cast<RawClosureData*>(func->ptr()->data_);
|
||||
RawFunction* parent_function = data->ptr()->parent_function_;
|
||||
return (parent_function->ptr()->data_ == reinterpret_cast<RawObject*>(func));
|
||||
}
|
||||
|
||||
|
||||
RawFunction* Function::New() {
|
||||
ASSERT(Object::function_class() != Class::null());
|
||||
RawObject* raw = Object::Allocate(Function::kClassId,
|
||||
|
@ -6383,10 +6398,15 @@ void Function::BuildSignatureParameters(
|
|||
|
||||
RawInstance* Function::ImplicitStaticClosure() const {
|
||||
if (implicit_static_closure() == Instance::null()) {
|
||||
ObjectStore* object_store = Isolate::Current()->object_store();
|
||||
const Context& context = Context::Handle(object_store->empty_context());
|
||||
const Instance& closure =
|
||||
Instance::Handle(Closure::New(*this, context, Heap::kOld));
|
||||
Isolate* isolate = Isolate::Current();
|
||||
ObjectStore* object_store = isolate->object_store();
|
||||
const Context& context = Context::Handle(isolate,
|
||||
object_store->empty_context());
|
||||
Instance& closure =
|
||||
Instance::Handle(isolate, Closure::New(*this, context, Heap::kOld));
|
||||
const char* error_str = NULL;
|
||||
closure ^= closure.CheckAndCanonicalize(&error_str);
|
||||
ASSERT(!closure.IsNull());
|
||||
set_implicit_static_closure(closure);
|
||||
}
|
||||
return implicit_static_closure();
|
||||
|
|
|
@ -2135,6 +2135,7 @@ class Function : public Object {
|
|||
bool IsImplicitStaticClosureFunction() const {
|
||||
return is_static() && IsImplicitClosureFunction();
|
||||
}
|
||||
bool static IsImplicitStaticClosureFunction(RawFunction* func);
|
||||
|
||||
// Returns true if this function represents an implicit instance closure
|
||||
// function.
|
||||
|
@ -2377,6 +2378,7 @@ FOR_EACH_FUNCTION_KIND_BIT(DEFINE_BIT)
|
|||
|
||||
FINAL_HEAP_OBJECT_IMPLEMENTATION(Function, Object);
|
||||
friend class Class;
|
||||
friend class SnapshotWriter;
|
||||
friend class Parser; // For set_eval_script.
|
||||
// RawFunction::VisitFunctionPointers accesses the private constructor of
|
||||
// Function.
|
||||
|
@ -7335,8 +7337,13 @@ class Closure : public AllStatic {
|
|||
// Indicates this class cannot be extended by dart code.
|
||||
return -kWordSize;
|
||||
}
|
||||
static RawFunction* GetFunction(RawObject* obj) {
|
||||
return *(reinterpret_cast<RawFunction**>(
|
||||
reinterpret_cast<intptr_t>(obj->ptr()) + function_offset()));
|
||||
}
|
||||
|
||||
friend class Class;
|
||||
friend class SnapshotWriter;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -542,7 +542,9 @@ class RawObject {
|
|||
friend class Array;
|
||||
friend class ByteBuffer;
|
||||
friend class Code;
|
||||
friend class Closure;
|
||||
friend class FreeListElement;
|
||||
friend class Function;
|
||||
friend class GCMarker;
|
||||
friend class ExternalTypedData;
|
||||
friend class ForwardList;
|
||||
|
@ -566,6 +568,7 @@ class RawObject {
|
|||
friend class TypedData;
|
||||
friend class TypedDataView;
|
||||
friend class WeakProperty; // StorePointer
|
||||
friend class Instance; // StorePointer
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(RawObject);
|
||||
|
@ -685,6 +688,8 @@ class RawPatchClass : public RawObject {
|
|||
RawObject** to() {
|
||||
return reinterpret_cast<RawObject**>(&ptr()->source_class_);
|
||||
}
|
||||
|
||||
friend class Function;
|
||||
};
|
||||
|
||||
|
||||
|
@ -772,6 +777,8 @@ class RawClosureData : public RawObject {
|
|||
RawObject** to() {
|
||||
return reinterpret_cast<RawObject**>(&ptr()->closure_);
|
||||
}
|
||||
|
||||
friend class Function;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -237,6 +237,46 @@ RawClass* SnapshotReader::ReadClassId(intptr_t object_id) {
|
|||
}
|
||||
|
||||
|
||||
RawObject* SnapshotReader::ReadStaticImplicitClosure(intptr_t object_id,
|
||||
intptr_t class_header) {
|
||||
ASSERT(kind_ == Snapshot::kMessage);
|
||||
|
||||
// First create a function object and associate it with the specified
|
||||
// 'object_id'.
|
||||
Function& func = Function::ZoneHandle(isolate(), Function::null());
|
||||
AddBackRef(object_id, &func, kIsDeserialized);
|
||||
|
||||
// Read the library/class/function information and lookup the function.
|
||||
str_ ^= ReadObjectImpl();
|
||||
library_ = Library::LookupLibrary(str_);
|
||||
if (library_.IsNull() || !library_.Loaded()) {
|
||||
SetReadException("Invalid Library object found in message.");
|
||||
}
|
||||
str_ ^= ReadObjectImpl();
|
||||
if (str_.Equals(Symbols::TopLevel())) {
|
||||
str_ ^= ReadObjectImpl();
|
||||
func = library_.LookupFunctionAllowPrivate(str_);
|
||||
} else {
|
||||
cls_ = library_.LookupClassAllowPrivate(str_);
|
||||
if (cls_.IsNull()) {
|
||||
OS::Print("Name of class not found %s\n", str_.ToCString());
|
||||
SetReadException("Invalid Class object found in message.");
|
||||
}
|
||||
cls_.EnsureIsFinalized(isolate());
|
||||
str_ ^= ReadObjectImpl();
|
||||
func = cls_.LookupFunctionAllowPrivate(str_);
|
||||
}
|
||||
if (func.IsNull()) {
|
||||
SetReadException("Invalid function object found in message.");
|
||||
}
|
||||
func = func.ImplicitClosureFunction();
|
||||
ASSERT(!func.IsNull());
|
||||
|
||||
// Return the associated implicit static closure.
|
||||
return func.ImplicitStaticClosure();
|
||||
}
|
||||
|
||||
|
||||
RawObject* SnapshotReader::ReadObjectImpl() {
|
||||
int64_t value = Read<int64_t>();
|
||||
if ((value & kSmiTagMask) == kSmiTag) {
|
||||
|
@ -312,7 +352,8 @@ RawObject* SnapshotReader::ReadObjectRef() {
|
|||
// Since we are only reading an object reference, If it is an instance kind
|
||||
// then we only need to figure out the class of the object and allocate an
|
||||
// instance of it. The individual fields will be read later.
|
||||
if (SerializedHeaderData::decode(class_header) == kInstanceObjectId) {
|
||||
intptr_t header_id = SerializedHeaderData::decode(class_header);
|
||||
if (header_id == kInstanceObjectId) {
|
||||
Instance& result = Instance::ZoneHandle(isolate(), Instance::null());
|
||||
AddBackRef(object_id, &result, kIsNotDeserialized);
|
||||
|
||||
|
@ -326,6 +367,12 @@ RawObject* SnapshotReader::ReadObjectRef() {
|
|||
result ^= Object::Allocate(cls_.id(), instance_size, HEAP_SPACE(kind_));
|
||||
}
|
||||
return result.raw();
|
||||
} else if (header_id == kStaticImplicitClosureObjectId) {
|
||||
// We skip the tags that have been written as the implicit static
|
||||
// closure is going to be created in this isolate or the canonical
|
||||
// version already created in the isolate will be used.
|
||||
ReadTags();
|
||||
return ReadStaticImplicitClosure(object_id, class_header);
|
||||
}
|
||||
ASSERT((class_header & kSmiTagMask) != kSmiTag);
|
||||
|
||||
|
@ -937,7 +984,8 @@ RawObject* SnapshotReader::ReadInlinedObject(intptr_t object_id) {
|
|||
// Read the class header information and lookup the class.
|
||||
intptr_t class_header = Read<int32_t>();
|
||||
intptr_t tags = ReadTags();
|
||||
if (SerializedHeaderData::decode(class_header) == kInstanceObjectId) {
|
||||
intptr_t header_id = SerializedHeaderData::decode(class_header);
|
||||
if (header_id == kInstanceObjectId) {
|
||||
// Object is regular dart instance.
|
||||
Instance* result = reinterpret_cast<Instance*>(GetBackRef(object_id));
|
||||
intptr_t instance_size = 0;
|
||||
|
@ -1002,6 +1050,11 @@ RawObject* SnapshotReader::ReadInlinedObject(intptr_t object_id) {
|
|||
ASSERT(!result->IsNull());
|
||||
}
|
||||
return result->raw();
|
||||
} else if (header_id == kStaticImplicitClosureObjectId) {
|
||||
// We do not use the tags as the implicit static closure
|
||||
// is going to be created in this isolate or the canonical
|
||||
// version already created in the isolate will be used.
|
||||
return ReadStaticImplicitClosure(object_id, class_header);
|
||||
}
|
||||
ASSERT((class_header & kSmiTagMask) != kSmiTag);
|
||||
intptr_t class_id = LookupInternalClass(class_header);
|
||||
|
@ -1215,10 +1268,10 @@ void SnapshotWriter::WriteObjectRef(RawObject* raw) {
|
|||
WriteInstanceRef(raw, cls);
|
||||
return;
|
||||
}
|
||||
// Object is being referenced, add it to the forward ref list and mark
|
||||
// it so that future references to this object in the snapshot will use
|
||||
// this object id. Mark it as not having been serialized yet so that we
|
||||
// will serialize the object when we go through the forward list.
|
||||
// Add object to the forward ref list and mark it so that future references
|
||||
// to this object in the snapshot will use this object id. Mark it as having
|
||||
// been serialized so that we do not serialize the object when we go through
|
||||
// the forward list.
|
||||
forward_list_.MarkAndAddObject(raw, kIsSerialized);
|
||||
switch (class_id) {
|
||||
#define SNAPSHOT_WRITE(clazz) \
|
||||
|
@ -1592,6 +1645,29 @@ void SnapshotWriter::WriteClassId(RawClass* cls) {
|
|||
}
|
||||
|
||||
|
||||
void SnapshotWriter::WriteStaticImplicitClosure(intptr_t object_id,
|
||||
RawFunction* func,
|
||||
intptr_t tags) {
|
||||
// Write out the serialization header value for this object.
|
||||
WriteInlinedObjectHeader(object_id);
|
||||
|
||||
// Indicate this is a static implicit closure object.
|
||||
Write<int32_t>(SerializedHeaderData::encode(kStaticImplicitClosureObjectId));
|
||||
|
||||
// Write out the tags.
|
||||
WriteTags(tags);
|
||||
|
||||
// Write out the library url, class name and signature function name.
|
||||
RawClass* cls = GetFunctionOwner(func);
|
||||
ASSERT(cls != Class::null());
|
||||
RawLibrary* library = cls->ptr()->library_;
|
||||
ASSERT(library != Library::null());
|
||||
WriteObjectImpl(library->ptr()->url_);
|
||||
WriteObjectImpl(cls->ptr()->name_);
|
||||
WriteObjectImpl(func->ptr()->name_);
|
||||
}
|
||||
|
||||
|
||||
void SnapshotWriter::ArrayWriteTo(intptr_t object_id,
|
||||
intptr_t array_kind,
|
||||
intptr_t tags,
|
||||
|
@ -1625,34 +1701,63 @@ void SnapshotWriter::ArrayWriteTo(intptr_t object_id,
|
|||
}
|
||||
|
||||
|
||||
void SnapshotWriter::CheckIfSerializable(RawClass* cls) {
|
||||
RawFunction* SnapshotWriter::IsSerializableClosure(RawClass* cls,
|
||||
RawObject* obj) {
|
||||
if (Class::IsSignatureClass(cls)) {
|
||||
// We do not allow closure objects in an isolate message.
|
||||
Isolate* isolate = Isolate::Current();
|
||||
HANDLESCOPE(isolate);
|
||||
// 'obj' is a closure as its class is a signature class, extract
|
||||
// the function object to check if this closure can be sent in an
|
||||
// isolate message.
|
||||
RawFunction* func = Closure::GetFunction(obj);
|
||||
// We only allow closure of top level methods or static functions in a
|
||||
// class to be sent in isolate messages.
|
||||
if (can_send_any_object() &&
|
||||
Function::IsImplicitStaticClosureFunction(func)) {
|
||||
return func;
|
||||
}
|
||||
// Not a closure of a top level method or static function, throw an
|
||||
// exception as we do not allow these objects to be serialized.
|
||||
HANDLESCOPE(isolate());
|
||||
|
||||
const Class& clazz = Class::Handle(isolate(), cls);
|
||||
const Function& errorFunc = Function::Handle(isolate(), func);
|
||||
ASSERT(!errorFunc.IsNull());
|
||||
|
||||
// All other closures are errors.
|
||||
const char* format = "Illegal argument in isolate message"
|
||||
" : (object is a closure - %s %s)";
|
||||
" : (object is a closure - %s %s)";
|
||||
UnmarkAll(); // Unmark objects now as we are about to print stuff.
|
||||
const Class& clazz = Class::Handle(isolate, cls);
|
||||
const Function& func = Function::Handle(isolate,
|
||||
clazz.signature_function());
|
||||
ASSERT(!func.IsNull());
|
||||
intptr_t len = OS::SNPrint(NULL, 0, format,
|
||||
clazz.ToCString(), func.ToCString()) + 1;
|
||||
char* chars = isolate->current_zone()->Alloc<char>(len);
|
||||
OS::SNPrint(chars, len, format, clazz.ToCString(), func.ToCString());
|
||||
clazz.ToCString(), errorFunc.ToCString()) + 1;
|
||||
char* chars = isolate()->current_zone()->Alloc<char>(len);
|
||||
OS::SNPrint(chars, len, format, clazz.ToCString(), errorFunc.ToCString());
|
||||
SetWriteException(Exceptions::kArgument, chars);
|
||||
}
|
||||
return Function::null();
|
||||
}
|
||||
|
||||
|
||||
RawClass* SnapshotWriter::GetFunctionOwner(RawFunction* func) {
|
||||
RawObject* owner = func->ptr()->owner_;
|
||||
uword tags = GetObjectTags(owner);
|
||||
intptr_t class_id = RawObject::ClassIdTag::decode(tags);
|
||||
if (class_id == kClassCid) {
|
||||
return reinterpret_cast<RawClass*>(owner);
|
||||
}
|
||||
ASSERT(class_id == kPatchClassCid);
|
||||
return reinterpret_cast<RawPatchClass*>(owner)->ptr()->patched_class_;
|
||||
}
|
||||
|
||||
|
||||
void SnapshotWriter::CheckForNativeFields(RawClass* cls) {
|
||||
if (cls->ptr()->num_native_fields_ != 0) {
|
||||
// We do not allow objects with native fields in an isolate message.
|
||||
Isolate* isolate = Isolate::Current();
|
||||
HANDLESCOPE(Isolate::Current());
|
||||
HANDLESCOPE(isolate());
|
||||
const char* format = "Illegal argument in isolate message"
|
||||
" : (object extends NativeWrapper - %s)";
|
||||
UnmarkAll(); // Unmark objects now as we are about to print stuff.
|
||||
const Class& clazz = Class::Handle(isolate, cls);
|
||||
const Class& clazz = Class::Handle(isolate(), cls);
|
||||
intptr_t len = OS::SNPrint(NULL, 0, format, clazz.ToCString()) + 1;
|
||||
char* chars = isolate->current_zone()->Alloc<char>(len);
|
||||
char* chars = isolate()->current_zone()->Alloc<char>(len);
|
||||
OS::SNPrint(chars, len, format, clazz.ToCString());
|
||||
SetWriteException(Exceptions::kArgument, chars);
|
||||
}
|
||||
|
@ -1673,11 +1778,20 @@ void SnapshotWriter::WriteInstance(intptr_t object_id,
|
|||
RawObject* raw,
|
||||
RawClass* cls,
|
||||
intptr_t tags) {
|
||||
// First check if object is a closure or has native fields.
|
||||
CheckIfSerializable(cls);
|
||||
// Check if the instance has native fields and throw an exception if it does.
|
||||
CheckForNativeFields(cls);
|
||||
|
||||
// Check if object is a closure that is serializable, if the object is a
|
||||
// closure that is not serializable this will throw an exception.
|
||||
RawFunction* func = IsSerializableClosure(cls, raw);
|
||||
if (func != Function::null()) {
|
||||
WriteStaticImplicitClosure(object_id, func, tags);
|
||||
return;
|
||||
}
|
||||
|
||||
// Object is regular dart instance.
|
||||
intptr_t next_field_offset =
|
||||
intptr_t next_field_offset = Class::IsSignatureClass(cls) ?
|
||||
Closure::InstanceSize() :
|
||||
cls->ptr()->next_field_offset_in_words_ << kWordSizeLog2;
|
||||
ASSERT(next_field_offset > 0);
|
||||
|
||||
|
@ -1713,8 +1827,25 @@ void SnapshotWriter::WriteInstance(intptr_t object_id,
|
|||
|
||||
|
||||
void SnapshotWriter::WriteInstanceRef(RawObject* raw, RawClass* cls) {
|
||||
// First check if object is a closure or has native fields.
|
||||
CheckIfSerializable(cls);
|
||||
// Check if the instance has native fields and throw an exception if it does.
|
||||
CheckForNativeFields(cls);
|
||||
|
||||
// Check if object is a closure that is serializable, if the object is a
|
||||
// closure that is not serializable this will throw an exception.
|
||||
RawFunction* func = IsSerializableClosure(cls, raw);
|
||||
if (func != Function::null()) {
|
||||
// Add object to the forward ref list and mark it so that future references
|
||||
// to this object in the snapshot will use this object id. Mark it as having
|
||||
// been serialized so that we do not serialize the object when we go through
|
||||
// the forward list.
|
||||
forward_list_.MarkAndAddObject(raw, kIsSerialized);
|
||||
uword tags = raw->ptr()->tags_;
|
||||
ASSERT(SerializedHeaderTag::decode(tags) == kObjectId);
|
||||
intptr_t object_id = SerializedHeaderData::decode(tags);
|
||||
tags = forward_list_.NodeForObjectId(object_id)->tags();
|
||||
WriteStaticImplicitClosure(object_id, func, tags);
|
||||
return;
|
||||
}
|
||||
|
||||
// Object is being referenced, add it to the forward ref list and mark
|
||||
// it so that future references to this object in the snapshot will use
|
||||
|
|
|
@ -347,6 +347,7 @@ class SnapshotReader : public BaseReader {
|
|||
RawObject* AllocateUninitialized(intptr_t class_id, intptr_t size);
|
||||
|
||||
RawClass* ReadClassId(intptr_t object_id);
|
||||
RawObject* ReadStaticImplicitClosure(intptr_t object_id, intptr_t cls_header);
|
||||
RawObject* ReadObjectImpl();
|
||||
RawObject* ReadObjectImpl(intptr_t header);
|
||||
RawObject* ReadObjectRef();
|
||||
|
@ -611,6 +612,9 @@ class SnapshotWriter : public BaseWriter {
|
|||
|
||||
void WriteObjectRef(RawObject* raw);
|
||||
void WriteClassId(RawClass* cls);
|
||||
void WriteStaticImplicitClosure(intptr_t object_id,
|
||||
RawFunction* func,
|
||||
intptr_t tags);
|
||||
void WriteObjectImpl(RawObject* raw);
|
||||
void WriteInlinedObject(RawObject* raw);
|
||||
void WriteForwardedObjects();
|
||||
|
@ -620,7 +624,9 @@ class SnapshotWriter : public BaseWriter {
|
|||
RawSmi* length,
|
||||
RawTypeArguments* type_arguments,
|
||||
RawObject* data[]);
|
||||
void CheckIfSerializable(RawClass* cls);
|
||||
RawFunction* IsSerializableClosure(RawClass* cls, RawObject* obj);
|
||||
RawClass* GetFunctionOwner(RawFunction* func);
|
||||
void CheckForNativeFields(RawClass* cls);
|
||||
void SetWriteException(Exceptions::ExceptionType type, const char* msg);
|
||||
void WriteInstance(intptr_t object_id,
|
||||
RawObject* raw,
|
||||
|
|
|
@ -22,7 +22,7 @@ enum {
|
|||
// Object id has been optimized away; reader should use next available id.
|
||||
kOmittedObjectId,
|
||||
|
||||
kClassIdsOffset = kDoubleObject,
|
||||
kClassIdsOffset = kOmittedObjectId,
|
||||
|
||||
// The class ids of predefined classes are included in this list
|
||||
// at an offset of kClassIdsOffset.
|
||||
|
@ -42,6 +42,7 @@ enum {
|
|||
kArrayType,
|
||||
|
||||
kInstanceObjectId,
|
||||
kStaticImplicitClosureObjectId,
|
||||
kMaxPredefinedObjectIds,
|
||||
kInvalidIndex = -1,
|
||||
};
|
||||
|
|
118
tests/isolate/function_send1_test.dart
Normal file
118
tests/isolate/function_send1_test.dart
Normal file
|
@ -0,0 +1,118 @@
|
|||
// Copyright (c) 2015, 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 "dart:isolate";
|
||||
import "dart:async";
|
||||
import "package:expect/expect.dart";
|
||||
import "package:async_helper/async_helper.dart";
|
||||
|
||||
void toplevel(port, message) { port.send("toplevel:$message"); }
|
||||
Function createFuncToplevel() => (p, m) { p.send(m); };
|
||||
class C {
|
||||
Function initializer;
|
||||
Function body;
|
||||
C() : initializer = ((p, m) { throw "initializer"; }) {
|
||||
body = (p, m) { throw "body"; };
|
||||
}
|
||||
static void staticFunc(port, message) { port.send("static:$message"); }
|
||||
static Function createFuncStatic() => (p, m) { throw "static expr"; };
|
||||
void instanceMethod(p, m) { throw "instanceMethod"; }
|
||||
Function createFuncMember() => (p, m) { throw "instance expr"; };
|
||||
void call(n, p) { throw "C"; }
|
||||
}
|
||||
|
||||
class Callable {
|
||||
void call(p, m) { p.send(["callable", m]); }
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
asyncStart();
|
||||
|
||||
// top-level functions, static functions, closures, instance methods
|
||||
// or function expressions are not sendable to an isolate spawned using
|
||||
// spawnUri.
|
||||
testUnsendable("toplevel", toplevel);
|
||||
testUnsendable("static", C.staticFunc);
|
||||
var c = new C();
|
||||
testUnsendable("instance method", c.instanceMethod);
|
||||
testUnsendable("static context expression", createFuncToplevel());
|
||||
testUnsendable("static context expression", C.createFuncStatic());
|
||||
testUnsendable("initializer context expression", c.initializer);
|
||||
testUnsendable("constructor context expression", c.body);
|
||||
testUnsendable("instance method context expression", c.createFuncMember());
|
||||
testUnsendable("toplevel", toplevel.call);
|
||||
testUnsendable("static", C.staticFunc.call);
|
||||
testUnsendable("callable object", new Callable().call);
|
||||
|
||||
asyncEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a receive port that expects exactly one message.
|
||||
// Pass the message to `callback` and return the sendPort.
|
||||
SendPort singleMessagePort(callback) {
|
||||
var p;
|
||||
p = new RawReceivePort((v) { p.close(); callback(v); });
|
||||
return p.sendPort;
|
||||
}
|
||||
|
||||
// A singleMessagePort that expects the message to be a specific value.
|
||||
SendPort expectMessagePort(message) {
|
||||
asyncStart();
|
||||
return singleMessagePort((v) {
|
||||
Expect.equals(message, v);
|
||||
asyncEnd();
|
||||
});
|
||||
}
|
||||
|
||||
// Creates a new isolate and a pair of ports that expect a single message
|
||||
// to be sent to the other isolate and back to the callback function.
|
||||
Future<SendPort> echoPort(callback(value)) {
|
||||
Completer completer = new Completer<SendPort>();
|
||||
SendPort replyPort = singleMessagePort(callback);
|
||||
RawReceivePort initPort;
|
||||
initPort = new RawReceivePort((p) {
|
||||
completer.complete(p);
|
||||
initPort.close();
|
||||
});
|
||||
return Isolate.spawn(_echo, [replyPort, initPort.sendPort])
|
||||
.then((isolate) => completer.future);
|
||||
}
|
||||
|
||||
void _echo(msg) {
|
||||
var replyPort = msg[0];
|
||||
RawReceivePort requestPort;
|
||||
requestPort = new RawReceivePort((msg) {
|
||||
replyPort.send(msg);
|
||||
requestPort.close(); // Single echo only.
|
||||
});
|
||||
msg[1].send(requestPort.sendPort);
|
||||
}
|
||||
|
||||
// Creates other isolate that waits for a single message, `msg`, on the returned
|
||||
// port, and executes it as `msg[0](msg[1],msg[2])` in the other isolate.
|
||||
Future<SendPort> callPort() {
|
||||
Completer completer = new Completer<SendPort>();
|
||||
SendPort initPort = singleMessagePort(completer.complete);
|
||||
return Isolate.spawn(_call, initPort)
|
||||
.then((_) => completer.future);
|
||||
}
|
||||
|
||||
void _call(initPort) {
|
||||
initPort.send(singleMessagePort(callFunc));
|
||||
}
|
||||
|
||||
void testUnsendable(name, func) {
|
||||
asyncStart();
|
||||
Isolate.spawnUri(Uri.parse("function_send_test.dart"), [], func)
|
||||
.then((v) => throw "allowed spawn direct?", onError: (e,s){ asyncEnd(); });
|
||||
asyncStart();
|
||||
Isolate.spawnUri(Uri.parse("function_send_test.dart"), [], [func])
|
||||
.then((v) => throw "allowed spawn wrapped?", onError: (e,s){ asyncEnd(); });
|
||||
}
|
||||
|
||||
void callFunc(message) {
|
||||
message[0](message[1], message[2]);
|
||||
}
|
|
@ -21,11 +21,9 @@ kill_self_test: Fail # Not implemented yet
|
|||
handle_error_test: Fail # Not implemented yet
|
||||
handle_error2_test: Fail # Not implemented yet
|
||||
handle_error3_test: Fail # Not implemented yet
|
||||
function_send_test: Fail # Not implemented yet
|
||||
|
||||
message3_test/constList_identical: RuntimeError # Issue 21816
|
||||
message3_test/constMap: RuntimeError # Issue 21816
|
||||
message3_test/fun: RuntimeError # Issue 21585
|
||||
message3_test/constInstance: RuntimeError # Issue 21816
|
||||
message3_test/byteBuffer: Crash # Issue 21818
|
||||
message3_test/int32x4: Crash # Issue 21818
|
||||
|
@ -77,6 +75,9 @@ spawn_uri_exported_main_test: RuntimeError # Issue 16549
|
|||
issue_21398_parent_isolate_test: RuntimeError # Issue 16549
|
||||
issue_21398_parent_isolate1_test: RuntimeError # Issue 16549
|
||||
issue_21398_parent_isolate2_test: Skip # Not implemented yet
|
||||
function_send_test: Fail # Not implemented yet
|
||||
function_send1_test: Fail # Not implemented yet
|
||||
message3_test/fun: RuntimeError # Issue 21585
|
||||
|
||||
[ $compiler == dart2js && ( $runtime == ff || $runtime == safari || $runtime == drt || $runtime == chrome || $runtime == chromeOnAndroid) ]
|
||||
isolate_stress_test: Pass, Slow # Issue 10697
|
||||
|
@ -112,6 +113,8 @@ simple_message_test/none: Fail, OK # Issue 13921 Dom isolates don't support spaw
|
|||
spawn_uri_missing_from_isolate_test: RuntimeError # Issue 17649
|
||||
spawn_uri_missing_test: SkipSlow # Times out.
|
||||
isolate_current_test: Fail, OK # Issue 13921 Dom isolates don't support spawnFunction
|
||||
function_send_test: Fail, OK # 13921 Dom isolates don't support spawnFunction
|
||||
function_send1_test: Fail, OK # 13921 Dom isolates don't support spawnFunction
|
||||
|
||||
[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
|
||||
browser/typed_data_message_test: StaticWarning
|
||||
|
|
Loading…
Reference in a new issue