1
0
mirror of https://github.com/dart-lang/sdk synced 2024-07-05 09:20:04 +00:00

[vm] Stricter checks when sending isolate messages between groups.

- Check against sending arbitrary classes via types.
 - Stop allowing any object from dart:core, dart:collection, dart:typed_data (effectively reverts 807eacae30).

`SendPort.send` does not require such objects are sendable, and there is no guarantee the receiving isolate can represent them.

TEST=ci
Bug: https://github.com/dart-lang/sdk/issues/50243
Change-Id: I7e9b0e9d83080d44a98b257cd8f2a58da5443a87
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/264725
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
This commit is contained in:
Ryan Macnak 2022-10-28 19:18:51 +00:00 committed by Commit Queue
parent ce591144b0
commit a8fe399c79
31 changed files with 821 additions and 1145 deletions

View File

@ -966,7 +966,7 @@ bool AotCallSpecializer::TryExpandCallThroughGetter(const Class& receiver_class,
// Ignore callsites like f.call() for now. Those need to be handled
// specially if f is a closure.
if (call->function_name().ptr() == Symbols::Call().ptr()) {
if (call->function_name().ptr() == Symbols::call().ptr()) {
return false;
}
@ -1017,7 +1017,7 @@ bool AotCallSpecializer::TryExpandCallThroughGetter(const Class& receiver_class,
}
InstanceCallInstr* invoke_call = new (Z) InstanceCallInstr(
call->source(), Symbols::Call(), Token::kILLEGAL,
call->source(), Symbols::call(), Token::kILLEGAL,
std::move(call_arguments), call->type_args_len(), call->argument_names(),
/*checked_argument_count=*/1,
thread()->compiler_state().GetNextDeoptId());

View File

@ -733,7 +733,7 @@ void Precompiler::PrecompileConstructors() {
void Precompiler::AddRoots() {
HANDLESCOPE(T);
AddSelector(Symbols::NoSuchMethod());
AddSelector(Symbols::Call()); // For speed, not correctness.
AddSelector(Symbols::call()); // For speed, not correctness.
// Add main as an entry point.
const Library& lib = Library::Handle(IG->object_store()->root_library());
@ -990,7 +990,7 @@ void Precompiler::AddCalleesOf(const Function& function, intptr_t gop_offset) {
}
static bool IsPotentialClosureCall(const String& selector) {
return selector.ptr() == Symbols::Call().ptr() ||
return selector.ptr() == Symbols::call().ptr() ||
selector.ptr() == Symbols::DynamicCall().ptr();
}
@ -1379,7 +1379,7 @@ const char* Precompiler::MustRetainFunction(const Function& function) {
// Use the same check for _Closure.call as in stack_trace.{h|cc}.
const auto& selector = String::Handle(Z, function.name());
if (selector.ptr() == Symbols::Call().ptr()) {
if (selector.ptr() == Symbols::call().ptr()) {
const auto& name = String::Handle(Z, function.QualifiedScrubbedName());
if (name.Equals(Symbols::_ClosureCall())) {
return "_Closure.call";
@ -2462,10 +2462,7 @@ static bool IsUserDefinedClass(Zone* zone,
return false;
}
const UntaggedClass* untagged_cls = cls.untag();
return ((untagged_cls->library() != object_store->core_library()) &&
(untagged_cls->library() != object_store->collection_library()) &&
(untagged_cls->library() != object_store->typed_data_library()));
return true;
}
/// Updates |visited| weak table with information about whether object

View File

@ -3141,7 +3141,7 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionInvocation(TokenPosition* p) {
SkipDartType(); // read function_type.
if (is_unchecked_closure_call) {
instructions += CheckNull(position, receiver_temp, Symbols::Call(),
instructions += CheckNull(position, receiver_temp, Symbols::call(),
/*clear_temp=*/false);
// Lookup the function in the closure.
instructions += LoadLocal(receiver_temp);

View File

@ -3245,7 +3245,7 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
const Class& closure_class =
Class::Handle(Z, IG->object_store()->closure_class());
const bool is_closure_call = (owner.ptr() == closure_class.ptr()) &&
field_name.Equals(Symbols::Call());
field_name.Equals(Symbols::call());
graph_entry_ =
new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
@ -3326,7 +3326,7 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
const intptr_t kNumArgsChecked = 1;
body +=
InstanceCall(TokenPosition::kMinSource,
is_dynamic_call ? Symbols::DynamicCall() : Symbols::Call(),
is_dynamic_call ? Symbols::DynamicCall() : Symbols::call(),
Token::kILLEGAL, descriptor.TypeArgsLen(),
descriptor.Count(), *argument_names, kNumArgsChecked);
}

File diff suppressed because it is too large Load Diff

View File

@ -275,7 +275,7 @@ ObjectPtr DartEntry::InvokeCallable(Thread* thread,
auto& instance =
Instance::CheckedHandle(zone, arguments.At(args_desc.FirstArgIndex()));
// For closures, use the name of the closure, not 'call'.
const String* target_name = &Symbols::Call();
const String* target_name = &Symbols::call();
if (instance.IsClosure()) {
auto const& function =
Function::Handle(zone, Closure::Cast(instance).function());

View File

@ -831,7 +831,7 @@ const Context& ActivationFrame::GetSavedCurrentContext() {
const auto variable_index = VariableIndex(var_info.index());
obj = GetStackVar(variable_index);
if (obj.IsClosure()) {
ASSERT(function().name() == Symbols::Call().ptr());
ASSERT(function().name() == Symbols::call().ptr());
ASSERT(function().IsInvokeFieldDispatcher());
// Closure.call frames.
ctx_ = Closure::Cast(obj).context();

View File

@ -87,7 +87,6 @@ class MessageSerializer;
class MessageDeserializer;
class ApiMessageSerializer;
class ApiMessageDeserializer;
class WeakPropertyMessageSerializationCluster;
class MessageSerializationCluster : public ZoneAllocated {
public:
@ -208,7 +207,6 @@ class BaseSerializer : public StackResource {
MallocWriteStream stream_;
MessageFinalizableData* finalizable_data_;
GrowableArray<MessageSerializationCluster*> clusters_;
WeakPropertyMessageSerializationCluster* ephemeron_cluster_;
intptr_t num_base_objects_;
intptr_t num_written_objects_;
intptr_t next_ref_index_;
@ -717,260 +715,6 @@ class TypeArgumentsMessageDeserializationCluster
}
};
class FunctionMessageSerializationCluster : public MessageSerializationCluster {
public:
FunctionMessageSerializationCluster()
: MessageSerializationCluster("Function",
MessagePhase::kBeforeTypes,
kFunctionCid) {}
~FunctionMessageSerializationCluster() {}
void Trace(MessageSerializer* s, Object* object) {
Function* func = static_cast<Function*>(object);
objects_.Add(func);
}
void WriteNodes(MessageSerializer* s) {
const intptr_t count = objects_.length();
s->WriteUnsigned(count);
Library& lib = Library::Handle(s->zone());
Class& cls = Class::Handle(s->zone());
String& str = String::Handle(s->zone());
for (intptr_t i = 0; i < count; i++) {
Function* func = objects_[i];
s->AssignRef(func);
cls ^= func->Owner();
lib = cls.library();
str = lib.url();
s->WriteAscii(str);
str = cls.Name();
s->WriteAscii(str);
str = func->name();
s->WriteAscii(str);
}
}
private:
GrowableArray<Function*> objects_;
};
class FunctionMessageDeserializationCluster
: public MessageDeserializationCluster {
public:
FunctionMessageDeserializationCluster()
: MessageDeserializationCluster("Function") {}
~FunctionMessageDeserializationCluster() {}
void ReadNodes(MessageDeserializer* d) {
const intptr_t count = d->ReadUnsigned();
String& uri = String::Handle(d->zone());
Library& lib = Library::Handle(d->zone());
String& cname = String::Handle(d->zone());
Class& cls = Class::Handle(d->zone());
String& fname = String::Handle(d->zone());
Function& func = Function::Handle(d->zone());
for (intptr_t i = 0; i < count; i++) {
uri = String::New(d->ReadAscii()); // Library URI.
cname = String::New(d->ReadAscii()); // Class name.
fname = String::New(d->ReadAscii()); // Function name.
lib = Library::LookupLibrary(d->thread(), uri);
if (UNLIKELY(lib.IsNull())) {
FATAL("Not found: %s %s %s", uri.ToCString(), cname.ToCString(),
fname.ToCString());
}
if (cname.Equals(Symbols::TopLevel())) {
cls = lib.toplevel_class();
} else {
cls = lib.LookupClass(cname);
}
if (UNLIKELY(cls.IsNull())) {
FATAL("Not found: %s %s %s", uri.ToCString(), cname.ToCString(),
fname.ToCString());
}
cls.EnsureIsFinalized(d->thread());
func = cls.LookupStaticFunction(fname);
if (UNLIKELY(func.IsNull())) {
FATAL("Not found: %s %s %s", uri.ToCString(), cname.ToCString(),
fname.ToCString());
}
d->AssignRef(func.ptr());
}
}
};
class InstanceMessageSerializationCluster : public MessageSerializationCluster {
public:
InstanceMessageSerializationCluster(bool is_canonical, intptr_t cid)
: MessageSerializationCluster("Instance",
is_canonical
? MessagePhase::kCanonicalInstances
: MessagePhase::kNonCanonicalInstances,
cid,
is_canonical),
cls_(Class::Handle()) {
cls_ = IsolateGroup::Current()->class_table()->At(cid);
next_field_offset_ = cls_.host_next_field_offset();
}
~InstanceMessageSerializationCluster() {}
void Trace(MessageSerializer* s, Object* object) {
Instance* instance = static_cast<Instance*>(object);
objects_.Add(instance);
const intptr_t next_field_offset = next_field_offset_;
const auto unboxed_fields_bitmap =
s->isolate_group()->class_table()->GetUnboxedFieldsMapAt(cid_);
for (intptr_t offset = Instance::NextFieldOffset();
offset < next_field_offset; offset += kCompressedWordSize) {
if (unboxed_fields_bitmap.Get(offset / kCompressedWordSize)) {
continue;
}
s->Push(reinterpret_cast<CompressedObjectPtr*>(
reinterpret_cast<uword>(instance->untag()) + offset)
->Decompress(instance->untag()->heap_base()));
}
}
void WriteNodes(MessageSerializer* s) {
s->WriteRef(cls_.ptr());
intptr_t count = objects_.length();
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
Instance* instance = objects_[i];
s->AssignRef(instance);
}
}
void WriteEdges(MessageSerializer* s) {
const intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
Instance* instance = objects_[i];
const intptr_t next_field_offset = next_field_offset_;
const auto unboxed_fields_bitmap =
s->isolate_group()->class_table()->GetUnboxedFieldsMapAt(cid_);
for (intptr_t offset = Instance::NextFieldOffset();
offset < next_field_offset; offset += kCompressedWordSize) {
if (unboxed_fields_bitmap.Get(offset / kCompressedWordSize)) {
// Writes 32 bits of the unboxed value at a time
const uword value = *reinterpret_cast<compressed_uword*>(
reinterpret_cast<uword>(instance->untag()) + offset);
s->WriteWordWith32BitWrites(value);
continue;
}
s->WriteRef(reinterpret_cast<CompressedObjectPtr*>(
reinterpret_cast<uword>(instance->untag()) + offset)
->Decompress(instance->untag()->heap_base()));
}
}
}
private:
Class& cls_;
intptr_t next_field_offset_;
GrowableArray<Instance*> objects_;
};
class InstanceMessageDeserializationCluster
: public MessageDeserializationCluster {
public:
explicit InstanceMessageDeserializationCluster(bool is_canonical)
: MessageDeserializationCluster("Instance", is_canonical),
cls_(Class::Handle()),
field_stores_(GrowableObjectArray::Handle(GrowableObjectArray::New())) {
}
~InstanceMessageDeserializationCluster() {}
void ReadNodes(MessageDeserializer* d) {
cls_ ^= d->ReadRef();
intptr_t count = d->ReadUnsigned();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(Instance::New(cls_));
}
}
void ReadEdges(MessageDeserializer* d) {
const intptr_t next_field_offset = cls_.host_next_field_offset();
const auto unboxed_fields_bitmap =
d->isolate_group()->class_table()->GetUnboxedFieldsMapAt(cls_.id());
#if !defined(DART_PRECOMPILED_RUNTIME)
const intptr_t type_argument_field_offset =
cls_.host_type_arguments_field_offset();
const bool use_field_guards = d->isolate_group()->use_field_guards();
const Array& field_map = Array::Handle(d->zone(), cls_.OffsetToFieldMap());
Field& field = Field::Handle(d->zone());
#endif
Instance& instance = Instance::Handle(d->zone());
Object& value = Object::Handle(d->zone());
for (intptr_t id = start_index_; id < stop_index_; id++) {
instance ^= d->Ref(id);
for (intptr_t offset = Instance::NextFieldOffset();
offset < next_field_offset; offset += kCompressedWordSize) {
if (unboxed_fields_bitmap.Get(offset / kCompressedWordSize)) {
compressed_uword* p = reinterpret_cast<compressed_uword*>(
reinterpret_cast<uword>(instance.untag()) + offset);
// Reads 32 bits of the unboxed value at a time
*p = d->ReadWordWith32BitReads();
continue;
}
value = d->ReadRef();
instance.SetFieldAtOffset(offset, value);
#if !defined(DART_PRECOMPILED_RUNTIME)
if (use_field_guards && (offset != type_argument_field_offset) &&
(value.ptr() != Object::sentinel().ptr())) {
field ^= field_map.At(offset >> kCompressedWordSizeLog2);
ASSERT(!field.IsNull());
ASSERT(field.HostOffset() == offset);
field_stores_.Add(field);
field_stores_.Add(value);
}
#endif
}
}
}
ObjectPtr PostLoad(MessageDeserializer* d) {
if (is_canonical()) {
SafepointMutexLocker ml(
d->isolate_group()->constant_canonicalization_mutex());
Instance& instance = Instance::Handle(d->zone());
for (intptr_t i = start_index_; i < stop_index_; i++) {
instance ^= d->Ref(i);
instance = instance.CanonicalizeLocked(d->thread());
d->UpdateRef(i, instance);
}
}
if (cls_.ptr() == d->isolate_group()->object_store()->expando_class()) {
const auto& expandos =
Array::Handle(d->zone(), Array::New(stop_index_ - start_index_));
auto& instance = Instance::Handle(d->zone());
for (intptr_t i = start_index_, j = 0; i < stop_index_; i++, j++) {
instance ^= d->Ref(i);
expandos.SetAt(j, instance);
}
return DartLibraryCalls::RehashObjectsInDartCore(d->thread(), expandos);
}
Field& field = Field::Handle(d->zone());
Object& value = Object::Handle(d->zone());
for (int i = 0; i < field_stores_.Length(); i += 2) {
field ^= field_stores_.At(i);
value = field_stores_.At(i + 1);
field.RecordStore(value);
}
return nullptr;
}
private:
Class& cls_;
GrowableObjectArray& field_stores_;
};
class TypeMessageSerializationCluster : public MessageSerializationCluster {
public:
explicit TypeMessageSerializationCluster(bool is_canonical)
@ -982,6 +726,11 @@ class TypeMessageSerializationCluster : public MessageSerializationCluster {
void Trace(MessageSerializer* s, Object* object) {
Type* type = static_cast<Type*>(object);
if (!type->IsTypeClassAllowedBySpawnUri()) {
s->IllegalObject(*object, "is a Type");
}
objects_.Add(type);
s->Push(type->type_class());
@ -1382,7 +1131,15 @@ class GrowableObjectArrayMessageSerializationCluster
GrowableObjectArray* array = static_cast<GrowableObjectArray*>(object);
objects_.Add(array);
s->Push(array->GetTypeArguments());
// Compensation for bogus type prefix optimization.
TypeArguments& args =
TypeArguments::Handle(s->zone(), array->untag()->type_arguments());
if (!args.IsNull() && (args.Length() != 1)) {
args = args.TruncatedTo(1);
array->untag()->set_type_arguments(args.ptr());
}
s->Push(array->untag()->type_arguments());
for (intptr_t i = 0, n = array->Length(); i < n; i++) {
s->Push(array->At(i));
}
@ -1402,7 +1159,7 @@ class GrowableObjectArrayMessageSerializationCluster
const intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
GrowableObjectArray* array = objects_[i];
s->WriteRef(array->GetTypeArguments());
s->WriteRef(array->untag()->type_arguments());
for (intptr_t i = 0, n = array->Length(); i < n; i++) {
s->WriteRef(array->At(i));
}
@ -2284,64 +2041,6 @@ class Simd128MessageDeserializationCluster
const intptr_t cid_;
};
class RegExpMessageSerializationCluster : public MessageSerializationCluster {
public:
RegExpMessageSerializationCluster()
: MessageSerializationCluster("RegExp",
MessagePhase::kNonCanonicalInstances,
kRegExpCid) {}
~RegExpMessageSerializationCluster() {}
void Trace(MessageSerializer* s, Object* object) {
RegExp* regexp = static_cast<RegExp*>(object);
objects_.Add(regexp);
s->Push(regexp->capture_name_map());
s->Push(regexp->pattern());
}
void WriteNodes(MessageSerializer* s) {
const intptr_t count = objects_.length();
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
RegExp* regexp = objects_[i];
s->AssignRef(regexp);
s->WriteRef(regexp->capture_name_map());
s->WriteRef(regexp->pattern());
s->Write<int32_t>(regexp->num_bracket_expressions());
s->Write<int32_t>(regexp->num_registers(true));
s->Write<int32_t>(regexp->num_registers(false));
s->Write<int>(regexp->flags().value());
}
}
private:
GrowableArray<RegExp*> objects_;
};
class RegExpMessageDeserializationCluster
: public MessageDeserializationCluster {
public:
RegExpMessageDeserializationCluster()
: MessageDeserializationCluster("RegExp") {}
~RegExpMessageDeserializationCluster() {}
void ReadNodes(MessageDeserializer* d) {
RegExp& regexp = RegExp::Handle(d->zone());
intptr_t count = d->ReadUnsigned();
for (intptr_t i = 0; i < count; i++) {
regexp = RegExp::New(d->zone());
d->AssignRef(regexp.ptr());
regexp.untag()->set_capture_name_map(static_cast<ArrayPtr>(d->ReadRef()));
regexp.untag()->set_pattern(static_cast<StringPtr>(d->ReadRef()));
regexp.set_num_bracket_expressions(d->Read<int32_t>());
regexp.set_num_registers(true, d->Read<int32_t>());
regexp.set_num_registers(false, d->Read<int32_t>());
regexp.set_flags(RegExpFlags(d->Read<int>()));
}
}
};
class SendPortMessageSerializationCluster : public MessageSerializationCluster {
public:
explicit SendPortMessageSerializationCluster(Zone* zone)
@ -2481,147 +2180,6 @@ class CapabilityMessageDeserializationCluster
}
};
class WeakPropertyMessageSerializationCluster
: public MessageSerializationCluster {
public:
WeakPropertyMessageSerializationCluster()
: MessageSerializationCluster("WeakProperty",
MessagePhase::kNonCanonicalInstances,
kWeakPropertyCid) {}
~WeakPropertyMessageSerializationCluster() {}
void Trace(MessageSerializer* s, Object* object) {
WeakProperty* property = static_cast<WeakProperty*>(object);
objects_.Add(property);
}
void RetraceEphemerons(MessageSerializer* s) {
for (intptr_t i = 0; i < objects_.length(); i++) {
WeakProperty* property = objects_[i];
if (s->HasRef(property->untag()->key())) {
s->Push(property->untag()->value());
}
}
}
void WriteNodes(MessageSerializer* s) {
const intptr_t count = objects_.length();
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
WeakProperty* property = objects_[i];
s->AssignRef(property);
}
}
void WriteEdges(MessageSerializer* s) {
const intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
WeakProperty* property = objects_[i];
if (s->HasRef(property->untag()->key())) {
s->WriteRef(property->untag()->key());
s->WriteRef(property->untag()->value());
} else {
s->WriteRef(Object::null());
s->WriteRef(Object::null());
}
}
}
private:
GrowableArray<WeakProperty*> objects_;
};
class WeakPropertyMessageDeserializationCluster
: public MessageDeserializationCluster {
public:
WeakPropertyMessageDeserializationCluster()
: MessageDeserializationCluster("WeakProperty") {}
~WeakPropertyMessageDeserializationCluster() {}
void ReadNodes(MessageDeserializer* d) {
const intptr_t count = d->ReadUnsigned();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(WeakProperty::New());
}
}
void ReadEdges(MessageDeserializer* d) {
ASSERT(!is_canonical()); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
WeakPropertyPtr property = static_cast<WeakPropertyPtr>(d->Ref(id));
property->untag()->set_key(d->ReadRef());
property->untag()->set_value(d->ReadRef());
}
}
};
class WeakReferenceMessageSerializationCluster
: public MessageSerializationCluster {
public:
WeakReferenceMessageSerializationCluster()
: MessageSerializationCluster("WeakReference",
MessagePhase::kNonCanonicalInstances,
kWeakReferenceCid) {}
~WeakReferenceMessageSerializationCluster() {}
void Trace(MessageSerializer* s, Object* object) {
WeakReference* reference = static_cast<WeakReference*>(object);
objects_.Add(reference);
s->Push(reference->untag()->type_arguments());
}
void WriteNodes(MessageSerializer* s) {
const intptr_t count = objects_.length();
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
WeakReference* reference = objects_[i];
s->AssignRef(reference);
}
}
void WriteEdges(MessageSerializer* s) {
const intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
WeakReference* reference = objects_[i];
if (s->HasRef(reference->untag()->target())) {
s->WriteRef(reference->untag()->target());
} else {
s->WriteRef(Object::null());
}
s->WriteRef(reference->untag()->type_arguments());
}
}
private:
GrowableArray<WeakReference*> objects_;
};
class WeakReferenceMessageDeserializationCluster
: public MessageDeserializationCluster {
public:
WeakReferenceMessageDeserializationCluster()
: MessageDeserializationCluster("WeakReference") {}
~WeakReferenceMessageDeserializationCluster() {}
void ReadNodes(MessageDeserializer* d) {
const intptr_t count = d->ReadUnsigned();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(WeakReference::New());
}
}
void ReadEdges(MessageDeserializer* d) {
ASSERT(!is_canonical()); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
WeakReferencePtr reference = static_cast<WeakReferencePtr>(d->Ref(id));
reference->untag()->set_target(d->ReadRef());
reference->untag()->set_type_arguments(
static_cast<TypeArgumentsPtr>(d->ReadRef()));
}
}
};
class LinkedHashMapMessageSerializationCluster
: public MessageSerializationCluster {
public:
@ -2641,6 +2199,14 @@ class LinkedHashMapMessageSerializationCluster
LinkedHashMap* map = static_cast<LinkedHashMap*>(object);
objects_.Add(map);
// Compensation for bogus type prefix optimization.
TypeArguments& args =
TypeArguments::Handle(s->zone(), map->untag()->type_arguments());
if (!args.IsNull() && (args.Length() != 2)) {
args = args.TruncatedTo(2);
map->untag()->set_type_arguments(args.ptr());
}
s->Push(map->untag()->type_arguments());
s->Push(map->untag()->data());
s->Push(map->untag()->used_data());
@ -2734,30 +2300,38 @@ class LinkedHashSetMessageSerializationCluster
~LinkedHashSetMessageSerializationCluster() {}
void Trace(MessageSerializer* s, Object* object) {
LinkedHashSet* map = static_cast<LinkedHashSet*>(object);
objects_.Add(map);
LinkedHashSet* set = static_cast<LinkedHashSet*>(object);
objects_.Add(set);
s->Push(map->untag()->type_arguments());
s->Push(map->untag()->data());
s->Push(map->untag()->used_data());
// Compensation for bogus type prefix optimization.
TypeArguments& args =
TypeArguments::Handle(s->zone(), set->untag()->type_arguments());
if (!args.IsNull() && (args.Length() != 1)) {
args = args.TruncatedTo(1);
set->untag()->set_type_arguments(args.ptr());
}
s->Push(set->untag()->type_arguments());
s->Push(set->untag()->data());
s->Push(set->untag()->used_data());
}
void WriteNodes(MessageSerializer* s) {
const intptr_t count = objects_.length();
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
LinkedHashSet* map = objects_[i];
s->AssignRef(map);
LinkedHashSet* set = objects_[i];
s->AssignRef(set);
}
}
void WriteEdges(MessageSerializer* s) {
const intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
LinkedHashSet* map = objects_[i];
s->WriteRef(map->untag()->type_arguments());
s->WriteRef(map->untag()->data());
s->WriteRef(map->untag()->used_data());
LinkedHashSet* set = objects_[i];
s->WriteRef(set->untag()->type_arguments());
s->WriteRef(set->untag()->data());
s->WriteRef(set->untag()->used_data());
}
}
@ -2830,6 +2404,14 @@ class ArrayMessageSerializationCluster : public MessageSerializationCluster {
Array* array = static_cast<Array*>(object);
objects_.Add(array);
// Compensation for bogus type prefix optimization.
TypeArguments& args =
TypeArguments::Handle(s->zone(), array->untag()->type_arguments());
if (!args.IsNull() && (args.Length() != 1)) {
args = args.TruncatedTo(1);
array->untag()->set_type_arguments(args.ptr());
}
s->Push(array->untag()->type_arguments());
intptr_t length = Smi::Value(array->untag()->length());
for (intptr_t i = 0; i < length; i++) {
@ -3201,7 +2783,6 @@ BaseSerializer::BaseSerializer(Thread* thread, Zone* zone)
stream_(100),
finalizable_data_(new MessageFinalizableData()),
clusters_(zone, 0),
ephemeron_cluster_(nullptr),
num_base_objects_(0),
num_written_objects_(0),
next_ref_index_(kFirstReference) {}
@ -3263,17 +2844,7 @@ void MessageSerializer::Trace(Object* object) {
}
if (cluster == nullptr) {
if (cid >= kNumPredefinedCids || cid == kInstanceCid) {
const Class& clazz =
Class::Handle(zone(), isolate_group()->class_table()->At(cid));
ObjectStore* object_store = isolate_group()->object_store();
if ((clazz.library() != object_store->core_library()) &&
(clazz.library() != object_store->collection_library()) &&
(clazz.library() != object_store->typed_data_library())) {
IllegalObject(*object, "is a regular instance");
}
if (clazz.num_native_fields() != 0) {
IllegalObject(*object, "is a NativeWrapper");
}
IllegalObject(*object, "is a regular instance");
}
// Keep the list in sync with the one in lib/isolate.cc
@ -3283,16 +2854,23 @@ void MessageSerializer::Trace(Object* object) {
}
ILLEGAL(Closure)
ILLEGAL(Finalizer)
ILLEGAL(FinalizerEntry)
ILLEGAL(FunctionType)
ILLEGAL(MirrorReference)
ILLEGAL(NativeFinalizer)
ILLEGAL(ReceivePort)
ILLEGAL(RegExp)
ILLEGAL(StackTrace)
ILLEGAL(SuspendState)
ILLEGAL(UserTag)
ILLEGAL(WeakProperty)
ILLEGAL(WeakReference)
// TODO(dartbug.com/49719): allow sending records as long as their
// elements are objects that can be sent.
ILLEGAL(RecordType)
ILLEGAL(Record)
// From "dart:ffi" we handle only Pointer/DynamicLibrary specially, since
// those are the only non-abstract classes (so we avoid checking more cids
@ -3302,10 +2880,6 @@ void MessageSerializer::Trace(Object* object) {
#undef ILLEGAL
if (cid >= kNumPredefinedCids || cid == kInstanceCid ||
cid == kByteBufferCid) {
Push(isolate_group()->class_table()->At(cid));
}
cluster = NewClusterForClass(cid, is_canonical);
clusters_.Add(cluster);
}
@ -3567,10 +3141,6 @@ MessageSerializationCluster* BaseSerializer::NewClusterForClass(
intptr_t cid,
bool is_canonical) {
Zone* Z = zone_;
if ((cid >= kNumPredefinedCids) || (cid == kInstanceCid) ||
(cid == kByteBufferCid)) {
return new (Z) InstanceMessageSerializationCluster(is_canonical, cid);
}
if (IsTypedDataViewClassId(cid) || cid == kByteDataViewCid ||
IsUnmodifiableTypedDataViewClassId(cid) ||
cid == kUnmodifiableByteDataViewCid) {
@ -3590,8 +3160,6 @@ MessageSerializationCluster* BaseSerializer::NewClusterForClass(
return new (Z) ClassMessageSerializationCluster();
case kTypeArgumentsCid:
return new (Z) TypeArgumentsMessageSerializationCluster(is_canonical);
case kFunctionCid:
return new (Z) FunctionMessageSerializationCluster();
case kTypeCid:
return new (Z) TypeMessageSerializationCluster(is_canonical);
case kTypeRefCid:
@ -3604,19 +3172,12 @@ MessageSerializationCluster* BaseSerializer::NewClusterForClass(
return new (Z) DoubleMessageSerializationCluster(Z, is_canonical);
case kGrowableObjectArrayCid:
return new (Z) GrowableObjectArrayMessageSerializationCluster();
case kRegExpCid:
return new (Z) RegExpMessageSerializationCluster();
case kSendPortCid:
return new (Z) SendPortMessageSerializationCluster(Z);
case kCapabilityCid:
return new (Z) CapabilityMessageSerializationCluster(Z);
case kTransferableTypedDataCid:
return new (Z) TransferableTypedDataMessageSerializationCluster();
case kWeakPropertyCid:
ephemeron_cluster_ = new (Z) WeakPropertyMessageSerializationCluster();
return ephemeron_cluster_;
case kWeakReferenceCid:
return new (Z) WeakReferenceMessageSerializationCluster();
case kLinkedHashMapCid:
case kImmutableLinkedHashMapCid:
return new (Z)
@ -3656,10 +3217,6 @@ MessageDeserializationCluster* BaseDeserializer::ReadCluster() {
const bool is_canonical = (cid_and_canonical & 0x1) == 0x1;
Zone* Z = zone_;
if ((cid >= kNumPredefinedCids) || (cid == kInstanceCid) ||
(cid == kByteBufferCid)) {
return new (Z) InstanceMessageDeserializationCluster(is_canonical);
}
if (IsTypedDataViewClassId(cid) || cid == kByteDataViewCid ||
IsUnmodifiableTypedDataViewClassId(cid) ||
cid == kUnmodifiableByteDataViewCid) {
@ -3684,9 +3241,6 @@ MessageDeserializationCluster* BaseDeserializer::ReadCluster() {
return new (Z) ClassMessageDeserializationCluster();
case kTypeArgumentsCid:
return new (Z) TypeArgumentsMessageDeserializationCluster(is_canonical);
case kFunctionCid:
ASSERT(!is_canonical);
return new (Z) FunctionMessageDeserializationCluster();
case kTypeCid:
return new (Z) TypeMessageDeserializationCluster(is_canonical);
case kTypeRefCid:
@ -3701,9 +3255,6 @@ MessageDeserializationCluster* BaseDeserializer::ReadCluster() {
case kGrowableObjectArrayCid:
ASSERT(!is_canonical);
return new (Z) GrowableObjectArrayMessageDeserializationCluster();
case kRegExpCid:
ASSERT(!is_canonical);
return new (Z) RegExpMessageDeserializationCluster();
case kSendPortCid:
ASSERT(!is_canonical);
return new (Z) SendPortMessageDeserializationCluster();
@ -3713,12 +3264,6 @@ MessageDeserializationCluster* BaseDeserializer::ReadCluster() {
case kTransferableTypedDataCid:
ASSERT(!is_canonical);
return new (Z) TransferableTypedDataMessageDeserializationCluster();
case kWeakPropertyCid:
ASSERT(!is_canonical);
return new (Z) WeakPropertyMessageDeserializationCluster();
case kWeakReferenceCid:
ASSERT(!is_canonical);
return new (Z) WeakReferenceMessageDeserializationCluster();
case kLinkedHashMapCid:
case kImmutableLinkedHashMapCid:
return new (Z)
@ -3805,15 +3350,7 @@ void MessageSerializer::Serialize(const Object& root) {
Push(root.ptr());
while (stack_.length() > 0) {
// Strong references.
while (stack_.length() > 0) {
Trace(stack_.RemoveLast());
}
// Ephemeron references.
if (ephemeron_cluster_ != nullptr) {
ephemeron_cluster_->RetraceEphemerons(this);
}
Trace(stack_.RemoveLast());
}
intptr_t num_objects = num_base_objects_ + num_written_objects_;

View File

@ -6962,6 +6962,19 @@ bool TypeArguments::CanShareFunctionTypeArguments(
return true;
}
TypeArgumentsPtr TypeArguments::TruncatedTo(intptr_t length) const {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const TypeArguments& result =
TypeArguments::Handle(zone, TypeArguments::New(length));
AbstractType& type = AbstractType::Handle(zone);
for (intptr_t i = 0; i < length; i++) {
type = TypeAt(i);
result.SetTypeAt(i, type);
}
return result.Canonicalize(thread);
}
bool TypeArguments::IsFinalized() const {
ASSERT(!IsNull());
AbstractType& type = AbstractType::Handle();
@ -10400,7 +10413,7 @@ bool Function::HasDynamicCallers(Zone* zone) const {
// Issue(dartbug.com/42719):
// Right now the metadata of _Closure.call says there are no dynamic callers -
// even though there can be. To be conservative we return true.
if ((name() == Symbols::GetCall().ptr() || name() == Symbols::Call().ptr()) &&
if ((name() == Symbols::GetCall().ptr() || name() == Symbols::call().ptr()) &&
Class::IsClosureClass(Owner())) {
return true;
}
@ -20053,7 +20066,7 @@ bool Instance::IsCallable(Function* function) const {
// Try to resolve a "call" method.
Zone* zone = Thread::Current()->zone();
Function& call_function = Function::Handle(
zone, Resolver::ResolveDynamicAnyArgs(zone, cls, Symbols::Call(),
zone, Resolver::ResolveDynamicAnyArgs(zone, cls, Symbols::call(),
/*allow_add=*/false));
if (call_function.IsNull()) {
return false;
@ -20724,6 +20737,48 @@ bool AbstractType::IsFfiPointerType() const {
return HasTypeClass() && type_class_id() == kPointerCid;
}
bool AbstractType::IsTypeClassAllowedBySpawnUri() const {
if (!HasTypeClass()) return false;
intptr_t cid = type_class_id();
if (cid == kBoolCid) return true;
if (cid == kDynamicCid) return true;
if (cid == kInstanceCid) return true; // Object.
if (cid == kNeverCid) return true;
if (cid == kNullCid) return true;
if (cid == kVoidCid) return true;
// These are not constant CID checks because kDoubleCid refers to _Double
// not double, etc.
ObjectStore* object_store = IsolateGroup::Current()->object_store();
Type& candidate_type = Type::Handle();
candidate_type = object_store->int_type();
if (cid == candidate_type.type_class_id()) return true;
candidate_type = object_store->double_type();
if (cid == candidate_type.type_class_id()) return true;
candidate_type = object_store->number_type();
if (cid == candidate_type.type_class_id()) return true;
candidate_type = object_store->string_type();
if (cid == candidate_type.type_class_id()) return true;
Class& candidate_cls = Class::Handle();
candidate_cls = object_store->list_class();
if (cid == candidate_cls.id()) return true;
candidate_cls = object_store->map_class();
if (cid == candidate_cls.id()) return true;
candidate_cls = object_store->set_class();
if (cid == candidate_cls.id()) return true;
candidate_cls = object_store->capability_class();
if (cid == candidate_cls.id()) return true;
candidate_cls = object_store->send_port_class();
if (cid == candidate_cls.id()) return true;
candidate_cls = object_store->transferable_class();
if (cid == candidate_cls.id()) return true;
return false;
}
AbstractTypePtr AbstractType::UnwrapFutureOr() const {
// Works properly for a TypeRef without dereferencing it.
if (!IsFutureOrType()) {
@ -27035,13 +27090,13 @@ EntryPointPragma FindEntryPointPragma(IsolateGroup* IG,
return EntryPointPragma::kAlways;
break;
}
if (pragma->ptr() == Symbols::Get().ptr()) {
if (pragma->ptr() == Symbols::get().ptr()) {
return EntryPointPragma::kGetterOnly;
}
if (pragma->ptr() == Symbols::Set().ptr()) {
if (pragma->ptr() == Symbols::set().ptr()) {
return EntryPointPragma::kSetterOnly;
}
if (pragma->ptr() == Symbols::Call().ptr()) {
if (pragma->ptr() == Symbols::call().ptr()) {
return EntryPointPragma::kCallOnly;
}
}

View File

@ -8067,6 +8067,7 @@ class TypeArguments : public Instance {
bool* with_runtime_check = nullptr) const;
bool CanShareFunctionTypeArguments(const Function& function,
bool* with_runtime_check = nullptr) const;
TypeArgumentsPtr TruncatedTo(intptr_t length) const;
// Return true if all types of this vector are finalized.
bool IsFinalized() const;
@ -8435,6 +8436,11 @@ class AbstractType : public Instance {
// non-nullable Object is also a catch-all type.
bool IsCatchAllType() const { return IsDynamicType() || IsObjectType(); }
// Returns true if this type has a type class permitted by SendPort.send for
// messages between isolates in different groups. Does not recursively visit
// type arguments.
bool IsTypeClassAllowedBySpawnUri() const;
// Check the subtype relationship.
bool IsSubtypeOf(const AbstractType& other,
Heap::Space space,

View File

@ -446,9 +446,15 @@ void ObjectStore::LazyInitCoreMembers() {
cls = core_lib.LookupClass(Symbols::Map());
ASSERT(!cls.IsNull());
map_class_.store(cls.ptr());
type ^= cls.RareType();
non_nullable_map_rare_type_.store(type.ptr());
cls = core_lib.LookupClass(Symbols::Set());
ASSERT(!cls.IsNull());
set_class_.store(cls.ptr());
auto& field = Field::Handle(zone);
cls = core_lib.LookupClassAllowPrivate(Symbols::_Enum());
@ -563,6 +569,18 @@ void ObjectStore::LazyInitIsolateMembers() {
auto& cls = Class::Handle(zone);
auto& function = Function::Handle(zone);
cls = isolate_lib.LookupClass(Symbols::Capability());
ASSERT(!cls.IsNull());
capability_class_.store(cls.ptr());
cls = isolate_lib.LookupClass(Symbols::SendPort());
ASSERT(!cls.IsNull());
send_port_class_.store(cls.ptr());
cls = isolate_lib.LookupClass(Symbols::TransferableTypedData());
ASSERT(!cls.IsNull());
transferable_class_.store(cls.ptr());
cls = isolate_lib.LookupClassAllowPrivate(Symbols::_RawReceivePortImpl());
ASSERT(!cls.IsNull());
const auto& error = cls.EnsureIsFinalized(thread);

View File

@ -46,6 +46,8 @@ class ObjectPointerVisitor;
LAZY_ASYNC, LAZY_ISOLATE, LAZY_INTERNAL, \
LAZY_FFI) \
LAZY_CORE(Class, list_class) \
LAZY_CORE(Class, map_class) \
LAZY_CORE(Class, set_class) \
LAZY_CORE(Type, non_nullable_list_rare_type) \
LAZY_CORE(Type, non_nullable_map_rare_type) \
LAZY_CORE(Field, enum_index_field) \
@ -60,6 +62,9 @@ class ObjectPointerVisitor;
LAZY_ASYNC(Type, non_nullable_future_rare_type) \
LAZY_ASYNC(Type, non_nullable_future_never_type) \
LAZY_ASYNC(Type, nullable_future_null_type) \
LAZY_ISOLATE(Class, send_port_class) \
LAZY_ISOLATE(Class, capability_class) \
LAZY_ISOLATE(Class, transferable_class) \
LAZY_ISOLATE(Function, lookup_port_handler) \
LAZY_ISOLATE(Function, lookup_open_ports) \
LAZY_ISOLATE(Function, handle_message_function) \

View File

@ -2636,7 +2636,7 @@ static ObjectPtr InvokeCallThroughGetterOrNoSuchMethod(
// o.foo(...) failed, invoke noSuchMethod is foo exists but has the wrong
// number of arguments, or try (o.foo).call(...)
if ((target_name.ptr() == Symbols::Call().ptr()) && receiver.IsClosure()) {
if ((target_name.ptr() == Symbols::call().ptr()) && receiver.IsClosure()) {
// Special case: closures are implemented with a call getter instead of a
// call method and with lazy dispatchers the field-invocation-dispatcher
// would perform the closure call.

View File

@ -31,7 +31,7 @@ class ObjectPointerVisitor;
V(BooleanExpression, "boolean expression") \
V(BoundsCheckForPartialInstantiation, "_boundsCheckForPartialInstantiation") \
V(ByteData, "ByteData") \
V(Call, "call") \
V(Capability, "Capability") \
V(CastError, "_CastError") \
V(CheckLoaded, "_checkLoaded") \
V(Class, "Class") \
@ -73,8 +73,8 @@ class ObjectPointerVisitor;
V(Default, "Default") \
V(DefaultLabel, ":L") \
V(DotCreate, "._create") \
V(DotFieldNI, ".fieldNI") \
V(DotFieldADI, ".fieldADI") \
V(DotFieldNI, ".fieldNI") \
V(DotRange, ".range") \
V(DotUnder, "._") \
V(DotValue, ".value") \
@ -82,8 +82,8 @@ class ObjectPointerVisitor;
V(Double, "double") \
V(Dynamic, "dynamic") \
V(DynamicCall, "dyn:call") \
V(DynamicCallCurrentNumProcessedVar, ":dyn_call_current_num_processed") \
V(DynamicCallCurrentFunctionVar, ":dyn_call_current_function") \
V(DynamicCallCurrentNumProcessedVar, ":dyn_call_current_num_processed") \
V(DynamicCallCurrentParamIndexVar, ":dyn_call_current_param_index") \
V(DynamicCallCurrentTypeParamVar, ":dyn_call_current_type_param") \
V(DynamicCallFunctionTypeArgsVar, ":dyn_call_function_type_args") \
@ -110,6 +110,7 @@ class ObjectPointerVisitor;
V(FfiFieldPacking, "packing") \
V(FfiFieldTypes, "fieldTypes") \
V(FfiFloat, "Float") \
V(FfiHandle, "Handle") \
V(FfiInt16, "Int16") \
V(FfiInt32, "Int32") \
V(FfiInt64, "Int64") \
@ -127,7 +128,6 @@ class ObjectPointerVisitor;
V(FfiUint64, "Uint64") \
V(FfiUint8, "Uint8") \
V(FfiVoid, "Void") \
V(FfiHandle, "Handle") \
V(Field, "Field") \
V(Finalizable, "Finalizable") \
V(FinalizerBase, "FinalizerBase") \
@ -150,7 +150,6 @@ class ObjectPointerVisitor;
V(FutureImpl, "_Future") \
V(FutureOr, "FutureOr") \
V(FutureValue, "Future.value") \
V(Get, "get") \
V(GetCall, "get:call") \
V(GetLength, "get:length") \
V(GetRuntimeType, "get:runtimeType") \
@ -193,6 +192,7 @@ class ObjectPointerVisitor;
V(ListFactory, "List.") \
V(ListFilledFactory, "List.filled") \
V(LoadLibrary, "_loadLibrary") \
V(LoadingUnit, "LoadingUnit") \
V(LocalVarDescriptors, "LocalVarDescriptors") \
V(Map, "Map") \
V(MapLiteralFactory, "Map._fromLiteral") \
@ -226,8 +226,9 @@ class ObjectPointerVisitor;
V(SavedTryContextVar, ":saved_try_context_var") \
V(Script, "Script") \
V(SecondArg, "y") \
V(SendPort, "SendPort") \
V(Sentinel, "Sentinel") \
V(Set, "set") \
V(Set, "Set") \
V(SetterPrefix, "set:") \
V(SingleTargetCache, "SingleTargetCache") \
V(SpaceIsFromSpace, " is from ") \
@ -239,13 +240,13 @@ class ObjectPointerVisitor;
V(Struct, "Struct") \
V(SubtypeTestCache, "SubtypeTestCache") \
V(SuspendStateVar, ":suspend_state_var") \
V(LoadingUnit, "LoadingUnit") \
V(SwitchExpr, ":switch_expr") \
V(Symbol, "Symbol") \
V(ThrowNew, "_throwNew") \
V(ThrowNewInvocation, "_throwNewInvocation") \
V(ThrowNewNullAssertion, "_throwNewNullAssertion") \
V(TopLevel, "::") \
V(TransferableTypedData, "TransferableTypedData") \
V(TruncDivOperator, "~/") \
V(TryFinallyReturnValue, ":try_finally_return_value") \
V(TwoByteString, "_TwoByteString") \
@ -262,11 +263,11 @@ class ObjectPointerVisitor;
V(Uint8ClampedList, "Uint8ClampedList") \
V(Uint8List, "Uint8List") \
V(UnaryMinus, "unary-") \
V(Union, "Union") \
V(UnsignedRightShiftOperator, ">>>") \
V(UnhandledException, "UnhandledException") \
V(Union, "Union") \
V(UnlinkedCall, "UnlinkedCall") \
V(UnsafeCast, "unsafeCast") \
V(UnsignedRightShiftOperator, ">>>") \
V(UnsupportedError, "UnsupportedError") \
V(UnwindError, "UnwindError") \
V(Value, "value") \
@ -277,7 +278,6 @@ class ObjectPointerVisitor;
V(_ByteBuffer, "_ByteBuffer") \
V(_ByteBufferDot_New, "_ByteBuffer._New") \
V(_ByteDataView, "_ByteDataView") \
V(_UnmodifiableByteDataView, "_UnmodifiableByteDataView") \
V(_CapabilityImpl, "_CapabilityImpl") \
V(_ClassMirror, "_ClassMirror") \
V(_Closure, "_Closure") \
@ -304,21 +304,6 @@ class ObjectPointerVisitor;
V(_ExternalUint8Array, "_ExternalUint8Array") \
V(_ExternalUint8ClampedArray, "_ExternalUint8ClampedArray") \
V(_FinalizerImpl, "_FinalizerImpl") \
V(_NativeFinalizer, "_NativeFinalizer") \
V(_UnmodifiableInt8ArrayView, "_UnmodifiableInt8ArrayView") \
V(_UnmodifiableInt16ArrayView, "_UnmodifiableInt16ArrayView") \
V(_UnmodifiableInt32ArrayView, "_UnmodifiableInt32ArrayView") \
V(_UnmodifiableInt64ArrayView, "_UnmodifiableInt64ArrayView") \
V(_UnmodifiableUint8ClampedArrayView, "_UnmodifiableUint8ClampedArrayView") \
V(_UnmodifiableUint8ArrayView, "_UnmodifiableUint8ArrayView") \
V(_UnmodifiableUint16ArrayView, "_UnmodifiableUint16ArrayView") \
V(_UnmodifiableUint32ArrayView, "_UnmodifiableUint32ArrayView") \
V(_UnmodifiableUint64ArrayView, "_UnmodifiableUint64ArrayView") \
V(_UnmodifiableFloat32ArrayView, "_UnmodifiableFloat32ArrayView") \
V(_UnmodifiableFloat64ArrayView, "_UnmodifiableFloat64ArrayView") \
V(_UnmodifiableInt32x4ArrayView, "_UnmodifiableInt32x4ArrayView") \
V(_UnmodifiableFloat32x4ArrayView, "_UnmodifiableFloat32x4ArrayView") \
V(_UnmodifiableFloat64x2ArrayView, "_UnmodifiableFloat64x2ArrayView") \
V(_Float32ArrayFactory, "Float32List.") \
V(_Float32ArrayView, "_Float32ArrayView") \
V(_Float32List, "_Float32List") \
@ -333,6 +318,7 @@ class ObjectPointerVisitor;
V(_Float64x2ArrayFactory, "Float64x2List.") \
V(_Float64x2ArrayView, "_Float64x2ArrayView") \
V(_Float64x2List, "_Float64x2List") \
V(_FunctionType, "_FunctionType") \
V(_FunctionTypeMirror, "_FunctionTypeMirror") \
V(_FutureListener, "_FutureListener") \
V(_GrowableList, "_GrowableList") \
@ -374,6 +360,7 @@ class ObjectPointerVisitor;
V(_MethodMirror, "_MethodMirror") \
V(_Mint, "_Mint") \
V(_MirrorReference, "_MirrorReference") \
V(_NativeFinalizer, "_NativeFinalizer") \
V(_ParameterMirror, "_ParameterMirror") \
V(_Random, "_Random") \
V(_RawReceivePortImpl, "_RawReceivePortImpl") \
@ -393,7 +380,6 @@ class ObjectPointerVisitor;
V(_SyncStreamController, "_SyncStreamController") \
V(_TransferableTypedDataImpl, "_TransferableTypedDataImpl") \
V(_Type, "_Type") \
V(_FunctionType, "_FunctionType") \
V(_TypeParameter, "_TypeParameter") \
V(_TypeRef, "_TypeRef") \
V(_TypeVariableMirror, "_TypeVariableMirror") \
@ -412,20 +398,34 @@ class ObjectPointerVisitor;
V(_Uint8ClampedArrayView, "_Uint8ClampedArrayView") \
V(_Uint8ClampedList, "_Uint8ClampedList") \
V(_Uint8List, "_Uint8List") \
V(_UnmodifiableByteDataView, "_UnmodifiableByteDataView") \
V(_UnmodifiableFloat32ArrayView, "_UnmodifiableFloat32ArrayView") \
V(_UnmodifiableFloat32x4ArrayView, "_UnmodifiableFloat32x4ArrayView") \
V(_UnmodifiableFloat64ArrayView, "_UnmodifiableFloat64ArrayView") \
V(_UnmodifiableFloat64x2ArrayView, "_UnmodifiableFloat64x2ArrayView") \
V(_UnmodifiableInt16ArrayView, "_UnmodifiableInt16ArrayView") \
V(_UnmodifiableInt32ArrayView, "_UnmodifiableInt32ArrayView") \
V(_UnmodifiableInt32x4ArrayView, "_UnmodifiableInt32x4ArrayView") \
V(_UnmodifiableInt64ArrayView, "_UnmodifiableInt64ArrayView") \
V(_UnmodifiableInt8ArrayView, "_UnmodifiableInt8ArrayView") \
V(_UnmodifiableUint16ArrayView, "_UnmodifiableUint16ArrayView") \
V(_UnmodifiableUint32ArrayView, "_UnmodifiableUint32ArrayView") \
V(_UnmodifiableUint64ArrayView, "_UnmodifiableUint64ArrayView") \
V(_UnmodifiableUint8ArrayView, "_UnmodifiableUint8ArrayView") \
V(_UnmodifiableUint8ClampedArrayView, "_UnmodifiableUint8ClampedArrayView") \
V(_UserTag, "_UserTag") \
V(_Utf8Decoder, "_Utf8Decoder") \
V(_VariableMirror, "_VariableMirror") \
V(_WeakProperty, "_WeakProperty") \
V(_WeakReferenceImpl, "_WeakReferenceImpl") \
V(_typedDataBase, "_typedDataBase") \
V(_await, "_await") \
V(_classRangeCheck, "_classRangeCheck") \
V(_current, "_current") \
V(_ensureScheduleImmediate, "_ensureScheduleImmediate") \
V(_future, "_future") \
V(_handleException, "_handleException") \
V(_handleMessage, "_handleMessage") \
V(_handleFinalizerMessage, "_handleFinalizerMessage") \
V(_handleMessage, "_handleMessage") \
V(_handleNativeFinalizerMessage, "_handleNativeFinalizerMessage") \
V(_hasValue, "_hasValue") \
V(_initAsync, "_initAsync") \
@ -462,6 +462,7 @@ class ObjectPointerVisitor;
V(_stateData, "_stateData") \
V(_suspendSyncStarAtStart, "_suspendSyncStarAtStart") \
V(_toString, "_toString") \
V(_typedDataBase, "_typedDataBase") \
V(_varData, "_varData") \
V(_wordCharacterMap, "_wordCharacterMap") \
V(_yieldAsyncStar, "_yieldAsyncStar") \
@ -470,6 +471,8 @@ class ObjectPointerVisitor;
V(add, "add") \
V(addStream, "addStream") \
V(asyncStarBody, "asyncStarBody") \
V(c_result, ":result") \
V(call, "call") \
V(callback, "callback") \
V(capture_length, ":capture_length") \
V(capture_start_index, ":capture_start_index") \
@ -480,6 +483,7 @@ class ObjectPointerVisitor;
V(current_position, ":current_position") \
V(dynamic_assert_assignable_stc_check, \
":dynamic_assert_assignable_stc_check") \
V(get, "get") \
V(index_temp, ":index_temp") \
V(isPaused, "isPaused") \
V(match_end_index, ":match_end_index") \
@ -489,8 +493,8 @@ class ObjectPointerVisitor;
V(options, "options") \
V(position_registers, ":position_registers") \
V(print, "print") \
V(c_result, ":result") \
V(result, "result") \
V(set, "set") \
V(stack, ":stack") \
V(stack_pointer, ":stack_pointer") \
V(start_index_param, ":start_index_param") \

View File

@ -7,6 +7,7 @@ part of "core_patch.dart";
// VM implementation of double.
@patch
@pragma("vm:entry-point")
class double {
@pragma("vm:external-name", "Double_parse")
external static double? _nativeParse(String str, int start, int end);

View File

@ -31,6 +31,7 @@ class ReceivePort {
}
@patch
@pragma("vm:entry-point")
class Capability {
@patch
factory Capability() => new _CapabilityImpl();
@ -684,6 +685,7 @@ class Isolate {
}
@patch
@pragma("vm:entry-point")
abstract class TransferableTypedData {
@patch
factory TransferableTypedData.fromList(List<TypedData> chunks) {

View File

@ -10,6 +10,7 @@ const int _maxUtf16 = 0xffff;
const int _maxUnicode = 0x10ffff;
@patch
@pragma("vm:entry-point")
class String {
@patch
factory String.fromCharCodes(Iterable<int> charCodes,

View File

@ -8,6 +8,7 @@ import "dart:typed_data" show Int64List;
/// VM implementation of int.
@patch
@pragma("vm:entry-point")
class int {
@patch
@pragma("vm:external-name", "Integer_fromEnvironment")

View File

@ -702,6 +702,7 @@ class Isolate {
///
/// [SendPort]s can be transmitted to other isolates, and they preserve equality
/// when sent.
@pragma("vm:entry-point")
abstract class SendPort implements Capability {
/// Sends an asynchronous [message] through this send port, to its
/// corresponding [ReceivePort].
@ -713,10 +714,11 @@ abstract class SendPort implements Capability {
/// - [int]
/// - [double]
/// - [String]
/// - [List] or [Map] (whose elements are any of these)
/// - [List], [Map] or [Set] (whose elements are any of these)
/// - [TransferableTypedData]
/// - [SendPort]
/// - [Capability]
/// - [Type] representing one of these types, Object, dynamic, void or Never
///
/// If the sender and receiver isolate share the same code (e.g. isolates
/// created via [Isolate.spawn]), the transitive object graph of [message] can

View File

@ -1,30 +0,0 @@
// 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:collection';
import 'dart:isolate';
main(List<String> args, message) {
var sendPort = message;
try {
var map0 = new LinkedHashMap<int, String>();
map0[1] = 'one';
map0[2] = 'two';
map0[3] = 'three';
var map1 = new LinkedHashMap<int, String>();
map1[4] = 'four';
map1[5] = 'five';
map1[6] = 'size';
var map2 = new LinkedHashMap<int, String>();
map2[7] = 'seven';
map2[8] = 'eight';
map2[9] = 'nine';
var map = new Map<int, LinkedHashMap<int, String>>.from(
{0: map0, 1: map1, 2: map2});
sendPort.send(map);
} catch (error) {
sendPort.send("Invalid Argument(s).");
}
}

View File

@ -45,32 +45,4 @@ main() {
receive2.close();
}, onError: (e) => print('$e'));
});
// Now spawn an isolate using spawnURI and have it
// send back a "literal" like LinkedHashMap object.
var receive3 = new ReceivePort();
Isolate.spawnUri(
Uri.parse('issue_24243_child3_isolate.dart'), [], receive3.sendPort)
.then((isolate) {
receive3.listen((msg) {
var map0 = new LinkedHashMap<int, String>();
map0[1] = 'one';
map0[2] = 'two';
map0[3] = 'three';
var map1 = new LinkedHashMap<int, String>();
map1[4] = 'four';
map1[5] = 'five';
map1[6] = 'size';
var map2 = new LinkedHashMap<int, String>();
map2[7] = 'seven';
map2[8] = 'eight';
map2[9] = 'nine';
Expect.isTrue(msg is Map<int, LinkedHashMap<int, String>>);
Expect.mapEquals(msg[0], map0);
Expect.mapEquals(msg[1], map1);
Expect.mapEquals(msg[2], map2);
Expect.throws(() => msg[0] = "throw an exception");
receive3.close();
}, onError: (e) => print('$e'));
});
}

View File

@ -38,7 +38,7 @@ testBadResolvePackage(port) async {
print("Spawned isolate's package config flag: $packageConfigStr");
print("Spawned isolate's loaded package config: $packageConfig");
print("Spawned isolate's resolved package path: $resolvedPkg");
port.send([resolvedPkg]);
port.send([resolvedPkg?.toString()]);
} catch (e, s) {
port.send("$e\n$s\n");
}

View File

@ -0,0 +1,34 @@
// Copyright (c) 2022, 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:async";
import "dart:io";
import "dart:isolate";
import "package:expect/expect.dart";
class Unsendable {}
Future<void> main(args, message) async {
if (args.contains("child")) {
var sendPort = message as SendPort;
var bad = <String, Unsendable?>{"a": null, "b": null};
Expect.throwsArgumentError(() => sendPort.send(bad));
var good = bad.keys.toList();
sendPort.send(good);
sendPort.send("done");
return;
}
final receivePort = RawReceivePort();
receivePort.handler = (msg) {
if (msg == "done") receivePort.close();
};
await Isolate.spawnUri(
Platform.script, <String>["child"], receivePort.sendPort,
errorsAreFatal: true);
}

View File

@ -0,0 +1,57 @@
// Copyright (c) 2022, 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:async";
import "dart:io";
import "dart:isolate";
import "package:expect/expect.dart";
class Foo {}
Type getType<T>() => T;
Future<void> main(args, message) async {
if (args.contains("child")) {
var sendPort = message as SendPort;
sendPort.send(getType<void>());
sendPort.send(Never);
sendPort.send(Object);
sendPort.send(dynamic);
sendPort.send(Null);
sendPort.send(bool);
sendPort.send(int);
sendPort.send(double);
sendPort.send(num);
sendPort.send(String);
sendPort.send(List);
sendPort.send(Map);
sendPort.send(Set);
sendPort.send(SendPort);
sendPort.send(Capability);
sendPort.send(TransferableTypedData);
Expect.throwsArgumentError(() => sendPort.send(Foo));
Expect.throwsArgumentError(() => sendPort.send(Socket));
Expect.throwsArgumentError(() => sendPort.send(getType<List<Foo>>()));
sendPort.send("done");
return;
}
final receivePort = RawReceivePort();
receivePort.handler = (msg) {
if (msg == "done") receivePort.close();
};
await Isolate.spawnUri(
Platform.script, <String>["child"], receivePort.sendPort,
errorsAreFatal: true);
}

View File

@ -2,29 +2,19 @@
// 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.
// VMOptions=--enable_fast_object_copy=true
// VMOptions=--enable_fast_object_copy=false
import 'dart:io';
import "dart:isolate";
import 'dart:typed_data';
import "package:expect/expect.dart";
void main(List<String> arguments, Object? message) async {
if (arguments.length == 1) {
assert(arguments[0] == 'helper');
await runHelper(message as SendPort);
} else {
await runTest();
}
}
Future<void> runTest() async {
main() async {
final port = ReceivePort();
// By spawning the isolate from an uri the newly isolate will run in it's own
// isolate group. This way we can test the message snapshot serialization
// code.
await Isolate.spawnUri(
Platform.script,
['helper'],
await Isolate.spawn(
runHelper,
port.sendPort,
);
final message = await port.first;

View File

@ -1,32 +0,0 @@
// 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.
// @dart = 2.9
import 'dart:collection';
import 'dart:isolate';
main(List<String> args, message) {
var sendPort = message;
try {
var map0 = new LinkedHashMap<int, String>();
map0[1] = 'one';
map0[2] = 'two';
map0[3] = 'three';
var map1 = new LinkedHashMap<int, String>();
map1[4] = 'four';
map1[5] = 'five';
map1[6] = 'size';
var map2 = new LinkedHashMap<int, String>();
map2[7] = 'seven';
map2[8] = 'eight';
map2[9] = 'nine';
var map = new Map<int, LinkedHashMap<int, String>>.from(
{0: map0, 1: map1, 2: map2});
sendPort.send(map);
} catch (error) {
sendPort.send("Invalid Argument(s).");
}
}

View File

@ -49,33 +49,4 @@ main() {
receive2.close();
}, onError: (e) => print('$e'));
});
// Now spawn an isolate using spawnURI and have it
// send back a "literal" like LinkedHashMap object.
var receive3 = new ReceivePort();
Isolate
.spawnUri(
Uri.parse('issue_24243_child3_isolate.dart'), [], receive3.sendPort)
.then((isolate) {
receive3.listen((msg) {
var map0 = new LinkedHashMap<int, String>();
map0[1] = 'one';
map0[2] = 'two';
map0[3] = 'three';
var map1 = new LinkedHashMap<int, String>();
map1[4] = 'four';
map1[5] = 'five';
map1[6] = 'size';
var map2 = new LinkedHashMap<int, String>();
map2[7] = 'seven';
map2[8] = 'eight';
map2[9] = 'nine';
Expect.isTrue(msg is Map<int, LinkedHashMap<int, String>>);
Expect.mapEquals(msg[0], map0);
Expect.mapEquals(msg[1], map1);
Expect.mapEquals(msg[2], map2);
Expect.throws(() => msg[0] = "throw an exception");
receive3.close();
}, onError: (e) => print('$e'));
});
}

View File

@ -40,7 +40,7 @@ testBadResolvePackage(port) async {
print("Spawned isolate's package config flag: $packageConfigStr");
print("Spawned isolate's loaded package config: $packageConfig");
print("Spawned isolate's resolved package path: $resolvedPkg");
port.send([resolvedPkg]);
port.send([resolvedPkg?.toString()]);
} catch (e, s) {
port.send("$e\n$s\n");
}

View File

@ -0,0 +1,36 @@
// Copyright (c) 2022, 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.
// @dart = 2.9
import "dart:async";
import "dart:io";
import "dart:isolate";
import "package:expect/expect.dart";
class Unsendable {}
Future<void> main(args, message) async {
if (args.contains("child")) {
var sendPort = message as SendPort;
var bad = <String, Unsendable>{"a": null, "b": null};
Expect.throwsArgumentError(() => sendPort.send(bad));
var good = bad.keys.toList();
sendPort.send(good);
sendPort.send("done");
return;
}
final receivePort = RawReceivePort();
receivePort.handler = (msg) {
if (msg == "done") receivePort.close();
};
await Isolate.spawnUri(
Platform.script, <String>["child"], receivePort.sendPort,
errorsAreFatal: true);
}

View File

@ -0,0 +1,59 @@
// Copyright (c) 2022, 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.
// @dart = 2.9
import "dart:async";
import "dart:io";
import "dart:isolate";
import "package:expect/expect.dart";
class Foo {}
Type getType<T>() => T;
Future<void> main(args, message) async {
if (args.contains("child")) {
var sendPort = message as SendPort;
sendPort.send(getType<void>());
sendPort.send(Never);
sendPort.send(Object);
sendPort.send(dynamic);
sendPort.send(Null);
sendPort.send(bool);
sendPort.send(int);
sendPort.send(double);
sendPort.send(num);
sendPort.send(String);
sendPort.send(List);
sendPort.send(Map);
sendPort.send(Set);
sendPort.send(SendPort);
sendPort.send(Capability);
sendPort.send(TransferableTypedData);
Expect.throwsArgumentError(() => sendPort.send(Foo));
Expect.throwsArgumentError(() => sendPort.send(Socket));
Expect.throwsArgumentError(() => sendPort.send(getType<List<Foo>>()));
sendPort.send("done");
return;
}
final receivePort = RawReceivePort();
receivePort.handler = (msg) {
if (msg == "done") receivePort.close();
};
await Isolate.spawnUri(
Platform.script, <String>["child"], receivePort.sendPort,
errorsAreFatal: true);
}

View File

@ -2,6 +2,9 @@
// 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.
// VMOptions=--enable_fast_object_copy=true
// VMOptions=--enable_fast_object_copy=false
// @dart = 2.9
import 'dart:io';
@ -10,23 +13,10 @@ import 'dart:typed_data';
import "package:expect/expect.dart";
void main(List<String> arguments, Object message) async {
if (arguments.length == 1) {
assert(arguments[0] == 'helper');
await runHelper(message as SendPort);
} else {
await runTest();
}
}
Future<void> runTest() async {
main() async {
final port = ReceivePort();
// By spawning the isolate from an uri the newly isolate will run in it's own
// isolate group. This way we can test the message snapshot serialization
// code.
await Isolate.spawnUri(
Platform.script,
['helper'],
await Isolate.spawn(
runHelper,
port.sendPort,
);
final message = await port.first;