| 1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 | // for details. All rights reserved. Use of this source code is governed by a |
| 3 | // BSD-style license that can be found in the LICENSE file. |
| 4 | |
| 5 | #include <memory> |
| 6 | |
| 7 | #include "vm/dart_api_message.h" |
| 8 | |
| 9 | #include "platform/undefined_behavior_sanitizer.h" |
| 10 | #include "platform/unicode.h" |
| 11 | #include "vm/object.h" |
| 12 | #include "vm/snapshot_ids.h" |
| 13 | #include "vm/symbols.h" |
| 14 | |
| 15 | namespace dart { |
| 16 | |
| 17 | static const int kNumInitialReferences = 4; |
| 18 | |
| 19 | ApiMessageReader::ApiMessageReader(Message* msg) |
| 20 | : BaseReader(msg->IsRaw() ? reinterpret_cast<uint8_t*>( |
| 21 | static_cast<uword>(msg->raw_obj())) |
| 22 | : msg->snapshot(), |
| 23 | msg->snapshot_length()), |
| 24 | zone_(NULL), |
| 25 | backward_references_(kNumInitialReferences), |
| 26 | vm_isolate_references_(kNumInitialReferences), |
| 27 | vm_symbol_references_(NULL), |
| 28 | finalizable_data_(msg->finalizable_data()) {} |
| 29 | |
| 30 | ApiMessageReader::~ApiMessageReader() {} |
| 31 | |
| 32 | void ApiMessageReader::Init() { |
| 33 | // We need to have an enclosing ApiNativeScope. |
| 34 | ASSERT(ApiNativeScope::Current() != NULL); |
| 35 | zone_ = ApiNativeScope::Current()->zone(); |
| 36 | ASSERT(zone_ != NULL); |
| 37 | |
| 38 | // Initialize marker objects used to handle Lists. |
| 39 | // TODO(sjesse): Remove this when message serialization format is |
| 40 | // updated. |
| 41 | memset(&type_arguments_marker, 0, sizeof(type_arguments_marker)); |
| 42 | memset(&dynamic_type_marker, 0, sizeof(dynamic_type_marker)); |
| 43 | type_arguments_marker.type = |
| 44 | static_cast<Dart_CObject_Type>(Dart_CObject_Internal::kTypeArguments); |
| 45 | dynamic_type_marker.type = |
| 46 | static_cast<Dart_CObject_Type>(Dart_CObject_Internal::kDynamicType); |
| 47 | } |
| 48 | |
| 49 | Dart_CObject* ApiMessageReader::ReadMessage() { |
| 50 | Init(); |
| 51 | if (PendingBytes() > 0) { |
| 52 | // Read the object out of the message. |
| 53 | return ReadObject(); |
| 54 | } else { |
| 55 | const ObjectPtr raw_obj = static_cast<const ObjectPtr>( |
| 56 | reinterpret_cast<uword>(CurrentBufferAddress())); |
| 57 | ASSERT(ApiObjectConverter::CanConvert(raw_obj)); |
| 58 | Dart_CObject* cobj = |
| 59 | reinterpret_cast<Dart_CObject*>(allocator(sizeof(Dart_CObject))); |
| 60 | ApiObjectConverter::Convert(raw_obj, cobj); |
| 61 | return cobj; |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | intptr_t ApiMessageReader::LookupInternalClass(intptr_t ) { |
| 66 | if (IsVMIsolateObject(class_header)) { |
| 67 | return GetVMIsolateObjectId(class_header); |
| 68 | } |
| 69 | ASSERT(SerializedHeaderTag::decode(class_header) == kObjectId); |
| 70 | return SerializedHeaderData::decode(class_header); |
| 71 | } |
| 72 | |
| 73 | Dart_CObject* ApiMessageReader::AllocateDartCObject(Dart_CObject_Type type) { |
| 74 | Dart_CObject* value = |
| 75 | reinterpret_cast<Dart_CObject*>(allocator(sizeof(Dart_CObject))); |
| 76 | ASSERT(value != NULL); |
| 77 | value->type = type; |
| 78 | return value; |
| 79 | } |
| 80 | |
| 81 | Dart_CObject* ApiMessageReader::AllocateDartCObjectUnsupported() { |
| 82 | return AllocateDartCObject(Dart_CObject_kUnsupported); |
| 83 | } |
| 84 | |
| 85 | Dart_CObject* ApiMessageReader::AllocateDartCObjectNull() { |
| 86 | return AllocateDartCObject(Dart_CObject_kNull); |
| 87 | } |
| 88 | |
| 89 | Dart_CObject* ApiMessageReader::AllocateDartCObjectBool(bool val) { |
| 90 | Dart_CObject* value = AllocateDartCObject(Dart_CObject_kBool); |
| 91 | value->value.as_bool = val; |
| 92 | return value; |
| 93 | } |
| 94 | |
| 95 | Dart_CObject* ApiMessageReader::AllocateDartCObjectInt32(int32_t val) { |
| 96 | Dart_CObject* value = AllocateDartCObject(Dart_CObject_kInt32); |
| 97 | value->value.as_int32 = val; |
| 98 | return value; |
| 99 | } |
| 100 | |
| 101 | Dart_CObject* ApiMessageReader::AllocateDartCObjectInt64(int64_t val) { |
| 102 | Dart_CObject* value = AllocateDartCObject(Dart_CObject_kInt64); |
| 103 | value->value.as_int64 = val; |
| 104 | return value; |
| 105 | } |
| 106 | |
| 107 | Dart_CObject* ApiMessageReader::AllocateDartCObjectDouble(double val) { |
| 108 | Dart_CObject* value = AllocateDartCObject(Dart_CObject_kDouble); |
| 109 | value->value.as_double = val; |
| 110 | return value; |
| 111 | } |
| 112 | |
| 113 | Dart_CObject* ApiMessageReader::AllocateDartCObjectString(intptr_t length) { |
| 114 | // Allocate a Dart_CObject structure followed by an array of chars |
| 115 | // for the string content. The pointer to the string content is set |
| 116 | // up to this area. |
| 117 | Dart_CObject* value = reinterpret_cast<Dart_CObject*>( |
| 118 | allocator(sizeof(Dart_CObject) + length + 1)); |
| 119 | ASSERT(value != NULL); |
| 120 | value->value.as_string = reinterpret_cast<char*>(value) + sizeof(*value); |
| 121 | value->type = Dart_CObject_kString; |
| 122 | return value; |
| 123 | } |
| 124 | |
| 125 | static int GetTypedDataSizeInBytes(Dart_TypedData_Type type) { |
| 126 | switch (type) { |
| 127 | case Dart_TypedData_kInt8: |
| 128 | case Dart_TypedData_kUint8: |
| 129 | case Dart_TypedData_kUint8Clamped: |
| 130 | return 1; |
| 131 | case Dart_TypedData_kInt16: |
| 132 | case Dart_TypedData_kUint16: |
| 133 | return 2; |
| 134 | case Dart_TypedData_kInt32: |
| 135 | case Dart_TypedData_kUint32: |
| 136 | case Dart_TypedData_kFloat32: |
| 137 | return 4; |
| 138 | case Dart_TypedData_kInt64: |
| 139 | case Dart_TypedData_kUint64: |
| 140 | case Dart_TypedData_kFloat64: |
| 141 | return 8; |
| 142 | case Dart_TypedData_kInt32x4: |
| 143 | case Dart_TypedData_kFloat32x4: |
| 144 | case Dart_TypedData_kFloat64x2: |
| 145 | return 16; |
| 146 | default: |
| 147 | break; |
| 148 | } |
| 149 | UNREACHABLE(); |
| 150 | return -1; |
| 151 | } |
| 152 | |
| 153 | Dart_CObject* ApiMessageReader::AllocateDartCObjectTypedData( |
| 154 | Dart_TypedData_Type type, |
| 155 | intptr_t length) { |
| 156 | // Allocate a Dart_CObject structure followed by an array of bytes |
| 157 | // for the byte array content. The pointer to the byte array content |
| 158 | // is set up to this area. |
| 159 | intptr_t length_in_bytes = GetTypedDataSizeInBytes(type) * length; |
| 160 | Dart_CObject* value = reinterpret_cast<Dart_CObject*>( |
| 161 | allocator(sizeof(Dart_CObject) + length_in_bytes)); |
| 162 | ASSERT(value != NULL); |
| 163 | value->type = Dart_CObject_kTypedData; |
| 164 | value->value.as_typed_data.type = type; |
| 165 | value->value.as_typed_data.length = length_in_bytes; |
| 166 | if (length > 0) { |
| 167 | value->value.as_typed_data.values = |
| 168 | reinterpret_cast<uint8_t*>(value) + sizeof(*value); |
| 169 | } else { |
| 170 | value->value.as_typed_data.values = NULL; |
| 171 | } |
| 172 | return value; |
| 173 | } |
| 174 | |
| 175 | Dart_CObject* ApiMessageReader::AllocateDartCObjectArray(intptr_t length) { |
| 176 | // Allocate a Dart_CObject structure followed by an array of |
| 177 | // pointers to Dart_CObject structures. The pointer to the array |
| 178 | // content is set up to this area. |
| 179 | Dart_CObject* value = reinterpret_cast<Dart_CObject*>( |
| 180 | allocator(sizeof(Dart_CObject) + length * sizeof(value))); |
| 181 | ASSERT(value != NULL); |
| 182 | value->type = Dart_CObject_kArray; |
| 183 | value->value.as_array.length = length; |
| 184 | if (length > 0) { |
| 185 | value->value.as_array.values = reinterpret_cast<Dart_CObject**>(value + 1); |
| 186 | } else { |
| 187 | value->value.as_array.values = NULL; |
| 188 | } |
| 189 | return value; |
| 190 | } |
| 191 | |
| 192 | Dart_CObject* ApiMessageReader::AllocateDartCObjectVmIsolateObj(intptr_t id) { |
| 193 | ObjectPtr raw = VmIsolateSnapshotObject(id); |
| 194 | intptr_t cid = raw->GetClassId(); |
| 195 | switch (cid) { |
| 196 | case kOneByteStringCid: { |
| 197 | OneByteStringPtr raw_str = static_cast<OneByteStringPtr>(raw); |
| 198 | const char* str = reinterpret_cast<const char*>(raw_str->ptr()->data()); |
| 199 | ASSERT(str != NULL); |
| 200 | Dart_CObject* object = NULL; |
| 201 | for (intptr_t i = 0; i < vm_isolate_references_.length(); i++) { |
| 202 | object = vm_isolate_references_.At(i); |
| 203 | if (object->type == Dart_CObject_kString) { |
| 204 | if (strcmp(str, object->value.as_string) == 0) { |
| 205 | return object; |
| 206 | } |
| 207 | } |
| 208 | } |
| 209 | object = CreateDartCObjectString(raw); |
| 210 | vm_isolate_references_.Add(object); |
| 211 | return object; |
| 212 | } |
| 213 | |
| 214 | case kMintCid: { |
| 215 | const Mint& obj = Mint::Handle(static_cast<MintPtr>(raw)); |
| 216 | int64_t value64 = obj.value(); |
| 217 | if ((kMinInt32 <= value64) && (value64 <= kMaxInt32)) { |
| 218 | return GetCanonicalMintObject(Dart_CObject_kInt32, value64); |
| 219 | } else { |
| 220 | return GetCanonicalMintObject(Dart_CObject_kInt64, value64); |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | default: |
| 225 | UNREACHABLE(); |
| 226 | return NULL; |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | Dart_CObject_Internal* ApiMessageReader::AllocateDartCObjectInternal( |
| 231 | Dart_CObject_Internal::Type type) { |
| 232 | Dart_CObject_Internal* value = reinterpret_cast<Dart_CObject_Internal*>( |
| 233 | allocator(sizeof(Dart_CObject_Internal))); |
| 234 | ASSERT(value != NULL); |
| 235 | value->type = static_cast<Dart_CObject_Type>(type); |
| 236 | return value; |
| 237 | } |
| 238 | |
| 239 | Dart_CObject_Internal* ApiMessageReader::AllocateDartCObjectClass() { |
| 240 | return AllocateDartCObjectInternal(Dart_CObject_Internal::kClass); |
| 241 | } |
| 242 | |
| 243 | ApiMessageReader::BackRefNode* ApiMessageReader::AllocateBackRefNode( |
| 244 | Dart_CObject* reference, |
| 245 | DeserializeState state) { |
| 246 | BackRefNode* value = |
| 247 | reinterpret_cast<BackRefNode*>(allocator(sizeof(BackRefNode))); |
| 248 | value->set_reference(reference); |
| 249 | value->set_state(state); |
| 250 | return value; |
| 251 | } |
| 252 | |
| 253 | Dart_CObject* ApiMessageReader::ReadInlinedObject(intptr_t object_id) { |
| 254 | // Read the class header information and lookup the class. |
| 255 | intptr_t = Read<int32_t>(); |
| 256 | intptr_t tags = ReadTags(); |
| 257 | USE(tags); |
| 258 | intptr_t class_id; |
| 259 | |
| 260 | // There is limited support for reading regular dart instances. Only |
| 261 | // typed data views are currently handled. |
| 262 | if (SerializedHeaderData::decode(class_header) == kInstanceObjectId) { |
| 263 | Dart_CObject_Internal* object = |
| 264 | reinterpret_cast<Dart_CObject_Internal*>(GetBackRef(object_id)); |
| 265 | if (object == NULL) { |
| 266 | object = |
| 267 | AllocateDartCObjectInternal(Dart_CObject_Internal::kUninitialized); |
| 268 | AddBackRef(object_id, object, kIsDeserialized); |
| 269 | // Read class of object. |
| 270 | object->cls = reinterpret_cast<Dart_CObject_Internal*>(ReadObjectImpl()); |
| 271 | ASSERT(object->cls->type == |
| 272 | static_cast<Dart_CObject_Type>(Dart_CObject_Internal::kClass)); |
| 273 | } |
| 274 | ASSERT(object->type == static_cast<Dart_CObject_Type>( |
| 275 | Dart_CObject_Internal::kUninitialized)); |
| 276 | return object; |
| 277 | } |
| 278 | |
| 279 | ASSERT((class_header & kSmiTagMask) != 0); |
| 280 | class_id = LookupInternalClass(class_header); |
| 281 | if ((class_id == kArrayCid) || (class_id == kImmutableArrayCid)) { |
| 282 | intptr_t len = ReadSmiValue(); |
| 283 | Dart_CObject* value = GetBackRef(object_id); |
| 284 | if (value == NULL) { |
| 285 | value = AllocateDartCObjectArray(len); |
| 286 | AddBackRef(object_id, value, kIsDeserialized); |
| 287 | } |
| 288 | // Skip type arguments. |
| 289 | // TODO(sjesse): Remove this when message serialization format is |
| 290 | // updated (currently type_arguments is leaked). |
| 291 | Dart_CObject* type_arguments = ReadObjectImpl(); |
| 292 | if (type_arguments != &type_arguments_marker && |
| 293 | type_arguments->type != Dart_CObject_kNull) { |
| 294 | return AllocateDartCObjectUnsupported(); |
| 295 | } |
| 296 | for (int i = 0; i < len; i++) { |
| 297 | value->value.as_array.values[i] = ReadObjectRef(); |
| 298 | } |
| 299 | return value; |
| 300 | } |
| 301 | |
| 302 | return ReadInternalVMObject(class_id, object_id); |
| 303 | } |
| 304 | |
| 305 | Dart_CObject* ApiMessageReader::ReadPredefinedSymbol(intptr_t object_id) { |
| 306 | ASSERT(Symbols::IsPredefinedSymbolId(object_id)); |
| 307 | intptr_t symbol_id = object_id - kMaxPredefinedObjectIds; |
| 308 | Dart_CObject* object; |
| 309 | if (vm_symbol_references_ != NULL && |
| 310 | (object = vm_symbol_references_[symbol_id]) != NULL) { |
| 311 | return object; |
| 312 | } |
| 313 | |
| 314 | if (vm_symbol_references_ == NULL) { |
| 315 | intptr_t size = |
| 316 | (sizeof(*vm_symbol_references_) * Symbols::kMaxPredefinedId); |
| 317 | vm_symbol_references_ = reinterpret_cast<Dart_CObject**>(allocator(size)); |
| 318 | memset(vm_symbol_references_, 0, size); |
| 319 | } |
| 320 | |
| 321 | object = CreateDartCObjectString(Symbols::GetPredefinedSymbol(object_id)); |
| 322 | ASSERT(vm_symbol_references_[symbol_id] == NULL); |
| 323 | vm_symbol_references_[symbol_id] = object; |
| 324 | return object; |
| 325 | } |
| 326 | |
| 327 | intptr_t ApiMessageReader::NextAvailableObjectId() const { |
| 328 | return backward_references_.length() + kMaxPredefinedObjectIds; |
| 329 | } |
| 330 | |
| 331 | Dart_CObject* ApiMessageReader::CreateDartCObjectString(ObjectPtr raw) { |
| 332 | ASSERT(IsOneByteStringClassId(raw->GetClassId())); |
| 333 | OneByteStringPtr raw_str = static_cast<OneByteStringPtr>(raw); |
| 334 | intptr_t len = Smi::Value(raw_str->ptr()->length_); |
| 335 | Dart_CObject* object = AllocateDartCObjectString(len); |
| 336 | char* p = object->value.as_string; |
| 337 | memmove(p, raw_str->ptr()->data(), len); |
| 338 | p[len] = '\0'; |
| 339 | return object; |
| 340 | } |
| 341 | |
| 342 | Dart_CObject* ApiMessageReader::GetCanonicalMintObject(Dart_CObject_Type type, |
| 343 | int64_t value64) { |
| 344 | Dart_CObject* object = NULL; |
| 345 | for (intptr_t i = 0; i < vm_isolate_references_.length(); i++) { |
| 346 | object = vm_isolate_references_.At(i); |
| 347 | if (object->type == type) { |
| 348 | if (value64 == object->value.as_int64) { |
| 349 | return object; |
| 350 | } |
| 351 | } |
| 352 | } |
| 353 | if (type == Dart_CObject_kInt32) { |
| 354 | object = AllocateDartCObjectInt32(static_cast<int32_t>(value64)); |
| 355 | } else { |
| 356 | object = AllocateDartCObjectInt64(value64); |
| 357 | } |
| 358 | vm_isolate_references_.Add(object); |
| 359 | return object; |
| 360 | } |
| 361 | |
| 362 | Dart_CObject* ApiMessageReader::ReadObjectRef() { |
| 363 | int64_t value64 = Read<int64_t>(); |
| 364 | if ((value64 & kSmiTagMask) == 0) { |
| 365 | int64_t untagged_value = value64 >> kSmiTagShift; |
| 366 | if ((kMinInt32 <= untagged_value) && (untagged_value <= kMaxInt32)) { |
| 367 | return AllocateDartCObjectInt32(static_cast<int32_t>(untagged_value)); |
| 368 | } else { |
| 369 | return AllocateDartCObjectInt64(untagged_value); |
| 370 | } |
| 371 | } |
| 372 | ASSERT((value64 <= kIntptrMax) && (value64 >= kIntptrMin)); |
| 373 | intptr_t value = static_cast<intptr_t>(value64); |
| 374 | if (IsVMIsolateObject(value)) { |
| 375 | return ReadVMIsolateObject(value); |
| 376 | } |
| 377 | if (SerializedHeaderTag::decode(value) == kObjectId) { |
| 378 | return ReadIndexedObject(SerializedHeaderData::decode(value)); |
| 379 | } |
| 380 | ASSERT(SerializedHeaderTag::decode(value) == kInlined); |
| 381 | // Read the class header information and lookup the class. |
| 382 | intptr_t = Read<int32_t>(); |
| 383 | |
| 384 | intptr_t object_id = SerializedHeaderData::decode(value); |
| 385 | if (object_id == kOmittedObjectId) { |
| 386 | object_id = NextAvailableObjectId(); |
| 387 | } |
| 388 | |
| 389 | intptr_t tags = ReadTags(); |
| 390 | USE(tags); |
| 391 | |
| 392 | // Reading of regular dart instances has limited support in order to |
| 393 | // read typed data views. |
| 394 | if (SerializedHeaderData::decode(class_header) == kInstanceObjectId) { |
| 395 | Dart_CObject_Internal* object = |
| 396 | AllocateDartCObjectInternal(Dart_CObject_Internal::kUninitialized); |
| 397 | AddBackRef(object_id, object, kIsNotDeserialized); |
| 398 | // Read class of object. |
| 399 | object->cls = reinterpret_cast<Dart_CObject_Internal*>(ReadObjectImpl()); |
| 400 | ASSERT(object->cls->type == |
| 401 | static_cast<Dart_CObject_Type>(Dart_CObject_Internal::kClass)); |
| 402 | return object; |
| 403 | } |
| 404 | ASSERT((class_header & kSmiTagMask) != 0); |
| 405 | intptr_t class_id = LookupInternalClass(class_header); |
| 406 | if ((class_id == kArrayCid) || (class_id == kImmutableArrayCid)) { |
| 407 | ASSERT(GetBackRef(object_id) == NULL); |
| 408 | intptr_t len = ReadSmiValue(); |
| 409 | Dart_CObject* value = AllocateDartCObjectArray(len); |
| 410 | AddBackRef(object_id, value, kIsNotDeserialized); |
| 411 | return value; |
| 412 | } |
| 413 | return ReadInternalVMObject(class_id, object_id); |
| 414 | } |
| 415 | |
| 416 | Dart_CObject* ApiMessageReader::ReadVMIsolateObject(intptr_t value) { |
| 417 | intptr_t object_id = GetVMIsolateObjectId(value); |
| 418 | if (object_id == kNullObject) { |
| 419 | return AllocateDartCObjectNull(); |
| 420 | } |
| 421 | if (object_id == kTrueValue) { |
| 422 | return AllocateDartCObjectBool(true); |
| 423 | } |
| 424 | if (object_id == kFalseValue) { |
| 425 | return AllocateDartCObjectBool(false); |
| 426 | } |
| 427 | if (object_id == kDoubleObject) { |
| 428 | return AllocateDartCObjectDouble(ReadDouble()); |
| 429 | } |
| 430 | if (Symbols::IsPredefinedSymbolId(object_id)) { |
| 431 | return ReadPredefinedSymbol(object_id); |
| 432 | } |
| 433 | // No other VM isolate objects are supported. |
| 434 | return AllocateDartCObjectNull(); |
| 435 | } |
| 436 | |
| 437 | Dart_CObject* ApiMessageReader::ReadInternalVMObject(intptr_t class_id, |
| 438 | intptr_t object_id) { |
| 439 | switch (class_id) { |
| 440 | case kClassCid: { |
| 441 | Dart_CObject_Internal* object = AllocateDartCObjectClass(); |
| 442 | AddBackRef(object_id, object, kIsDeserialized); |
| 443 | object->internal.as_class.library_url = ReadObjectImpl(); |
| 444 | ASSERT(object->internal.as_class.library_url->type == |
| 445 | Dart_CObject_kString); |
| 446 | object->internal.as_class.class_name = ReadObjectImpl(); |
| 447 | ASSERT(object->internal.as_class.class_name->type == |
| 448 | Dart_CObject_kString); |
| 449 | return object; |
| 450 | } |
| 451 | case kTypeArgumentsCid: { |
| 452 | // TODO(sjesse): Remove this when message serialization format is |
| 453 | // updated (currently length is leaked). |
| 454 | Dart_CObject* value = &type_arguments_marker; |
| 455 | AddBackRef(object_id, value, kIsDeserialized); |
| 456 | Dart_CObject* length = ReadObjectImpl(); |
| 457 | ASSERT(length->type == Dart_CObject_kInt32); |
| 458 | // The instantiations_ field is only written to a full snapshot. |
| 459 | for (int i = 0; i < length->value.as_int32; i++) { |
| 460 | Dart_CObject* type = ReadObjectImpl(); |
| 461 | if (type != &dynamic_type_marker) { |
| 462 | return AllocateDartCObjectUnsupported(); |
| 463 | } |
| 464 | } |
| 465 | return value; |
| 466 | } |
| 467 | case kTypeParameterCid: { |
| 468 | Dart_CObject* value = &dynamic_type_marker; |
| 469 | AddBackRef(object_id, value, kIsDeserialized); |
| 470 | intptr_t index = Read<int32_t>(); |
| 471 | USE(index); |
| 472 | intptr_t token_index = Read<int32_t>(); |
| 473 | USE(token_index); |
| 474 | int8_t type_state = Read<int8_t>(); |
| 475 | USE(type_state); |
| 476 | Dart_CObject* parameterized_class = ReadObjectImpl(); |
| 477 | // The type parameter is finalized, therefore parameterized_class is null. |
| 478 | ASSERT(parameterized_class->type == Dart_CObject_kNull); |
| 479 | Dart_CObject* name = ReadObjectImpl(); |
| 480 | ASSERT(name->type == Dart_CObject_kString); |
| 481 | return value; |
| 482 | } |
| 483 | case kMintCid: { |
| 484 | int64_t value64 = Read<int64_t>(); |
| 485 | Dart_CObject* object; |
| 486 | if ((kMinInt32 <= value64) && (value64 <= kMaxInt32)) { |
| 487 | object = AllocateDartCObjectInt32(static_cast<int32_t>(value64)); |
| 488 | } else { |
| 489 | object = AllocateDartCObjectInt64(value64); |
| 490 | } |
| 491 | AddBackRef(object_id, object, kIsDeserialized); |
| 492 | return object; |
| 493 | } |
| 494 | case kDoubleCid: { |
| 495 | // Doubles are handled specially when being sent as part of message |
| 496 | // snapshots. |
| 497 | UNREACHABLE(); |
| 498 | } |
| 499 | case kOneByteStringCid: { |
| 500 | intptr_t len = ReadSmiValue(); |
| 501 | uint8_t* latin1 = |
| 502 | reinterpret_cast<uint8_t*>(allocator(len * sizeof(uint8_t))); |
| 503 | intptr_t utf8_len = 0; |
| 504 | for (intptr_t i = 0; i < len; i++) { |
| 505 | latin1[i] = Read<uint8_t>(); |
| 506 | utf8_len += Utf8::Length(latin1[i]); |
| 507 | } |
| 508 | Dart_CObject* object = AllocateDartCObjectString(utf8_len); |
| 509 | AddBackRef(object_id, object, kIsDeserialized); |
| 510 | char* p = object->value.as_string; |
| 511 | for (intptr_t i = 0; i < len; i++) { |
| 512 | p += Utf8::Encode(latin1[i], p); |
| 513 | } |
| 514 | *p = '\0'; |
| 515 | ASSERT(p == (object->value.as_string + utf8_len)); |
| 516 | return object; |
| 517 | } |
| 518 | case kTwoByteStringCid: { |
| 519 | intptr_t len = ReadSmiValue(); |
| 520 | uint16_t* utf16 = |
| 521 | reinterpret_cast<uint16_t*>(allocator(len * sizeof(uint16_t))); |
| 522 | intptr_t utf8_len = 0; |
| 523 | // Read all the UTF-16 code units. |
| 524 | for (intptr_t i = 0; i < len; i++) { |
| 525 | utf16[i] = Read<uint16_t>(); |
| 526 | } |
| 527 | // Calculate the UTF-8 length and check if the string can be |
| 528 | // UTF-8 encoded. |
| 529 | bool valid = true; |
| 530 | intptr_t i = 0; |
| 531 | while (i < len && valid) { |
| 532 | int32_t ch = Utf16::Next(utf16, &i, len); |
| 533 | utf8_len += Utf8::Length(ch); |
| 534 | valid = !Utf16::IsSurrogate(ch); |
| 535 | } |
| 536 | if (!valid) { |
| 537 | return AllocateDartCObjectUnsupported(); |
| 538 | } |
| 539 | Dart_CObject* object = AllocateDartCObjectString(utf8_len); |
| 540 | AddBackRef(object_id, object, kIsDeserialized); |
| 541 | char* p = object->value.as_string; |
| 542 | i = 0; |
| 543 | while (i < len) { |
| 544 | p += Utf8::Encode(Utf16::Next(utf16, &i, len), p); |
| 545 | } |
| 546 | *p = '\0'; |
| 547 | ASSERT(p == (object->value.as_string + utf8_len)); |
| 548 | return object; |
| 549 | } |
| 550 | case kSendPortCid: { |
| 551 | int64_t value64 = Read<int64_t>(); |
| 552 | int64_t originId = Read<uint64_t>(); |
| 553 | Dart_CObject* object = AllocateDartCObject(Dart_CObject_kSendPort); |
| 554 | object->value.as_send_port.id = value64; |
| 555 | object->value.as_send_port.origin_id = originId; |
| 556 | AddBackRef(object_id, object, kIsDeserialized); |
| 557 | return object; |
| 558 | } |
| 559 | case kCapabilityCid: { |
| 560 | int64_t id = Read<int64_t>(); |
| 561 | Dart_CObject* object = AllocateDartCObject(Dart_CObject_kCapability); |
| 562 | object->value.as_capability.id = id; |
| 563 | AddBackRef(object_id, object, kIsDeserialized); |
| 564 | return object; |
| 565 | } |
| 566 | |
| 567 | #define READ_TYPED_DATA(tname, ctype) \ |
| 568 | { \ |
| 569 | intptr_t len = ReadSmiValue(); \ |
| 570 | auto type = Dart_TypedData_k##tname; \ |
| 571 | intptr_t length_in_bytes = GetTypedDataSizeInBytes(type) * len; \ |
| 572 | Dart_CObject* object = \ |
| 573 | reinterpret_cast<Dart_CObject*>(allocator(sizeof(Dart_CObject))); \ |
| 574 | ASSERT(object != NULL); \ |
| 575 | object->type = Dart_CObject_kTypedData; \ |
| 576 | object->value.as_typed_data.type = type; \ |
| 577 | object->value.as_typed_data.length = length_in_bytes; \ |
| 578 | if (len > 0) { \ |
| 579 | Align(Zone::kAlignment); \ |
| 580 | object->value.as_typed_data.values = \ |
| 581 | const_cast<uint8_t*>(CurrentBufferAddress()); \ |
| 582 | Advance(length_in_bytes); \ |
| 583 | } else { \ |
| 584 | object->value.as_typed_data.values = NULL; \ |
| 585 | } \ |
| 586 | AddBackRef(object_id, object, kIsDeserialized); \ |
| 587 | return object; \ |
| 588 | } |
| 589 | |
| 590 | #define READ_EXTERNAL_TYPED_DATA(tname, ctype) \ |
| 591 | { \ |
| 592 | intptr_t len = ReadSmiValue(); \ |
| 593 | auto type = Dart_TypedData_k##tname; \ |
| 594 | intptr_t length_in_bytes = GetTypedDataSizeInBytes(type) * len; \ |
| 595 | Dart_CObject* object = \ |
| 596 | reinterpret_cast<Dart_CObject*>(allocator(sizeof(Dart_CObject))); \ |
| 597 | ASSERT(object != NULL); \ |
| 598 | object->type = Dart_CObject_kTypedData; \ |
| 599 | object->value.as_typed_data.type = type; \ |
| 600 | object->value.as_typed_data.length = length_in_bytes; \ |
| 601 | object->value.as_typed_data.values = \ |
| 602 | reinterpret_cast<uint8_t*>(finalizable_data_->Get().data); \ |
| 603 | AddBackRef(object_id, object, kIsDeserialized); \ |
| 604 | return object; \ |
| 605 | } |
| 606 | |
| 607 | #define READ_TYPED_DATA_VIEW(tname, ctype) \ |
| 608 | { \ |
| 609 | Dart_CObject_Internal* object = \ |
| 610 | AllocateDartCObjectInternal(Dart_CObject_Internal::kUninitialized); \ |
| 611 | AddBackRef(object_id, object, kIsDeserialized); \ |
| 612 | object->type = \ |
| 613 | static_cast<Dart_CObject_Type>(Dart_CObject_Internal::kView); \ |
| 614 | object->internal.as_view.offset_in_bytes = ReadSmiValue(); \ |
| 615 | object->internal.as_view.length = ReadSmiValue(); \ |
| 616 | object->internal.as_view.buffer = ReadObjectImpl(); \ |
| 617 | Dart_CObject* buffer = object->internal.as_view.buffer; \ |
| 618 | RELEASE_ASSERT(buffer->type == Dart_CObject_kTypedData); \ |
| 619 | \ |
| 620 | /* Now turn the view into a byte array.*/ \ |
| 621 | const Dart_TypedData_Type type = Dart_TypedData_k##tname; \ |
| 622 | object->type = Dart_CObject_kTypedData; \ |
| 623 | object->value.as_typed_data.type = type; \ |
| 624 | object->value.as_typed_data.length = \ |
| 625 | object->internal.as_view.length * GetTypedDataSizeInBytes(type); \ |
| 626 | object->value.as_typed_data.values = \ |
| 627 | buffer->value.as_typed_data.values + \ |
| 628 | object->internal.as_view.offset_in_bytes; \ |
| 629 | return object; \ |
| 630 | } |
| 631 | |
| 632 | #define TYPED_DATA_LIST(V) \ |
| 633 | V(Int8, int8_t) \ |
| 634 | V(Uint8, uint8_t) \ |
| 635 | V(Uint8Clamped, uint8_t) \ |
| 636 | V(Int16, int16_t) \ |
| 637 | V(Uint16, uint16_t) \ |
| 638 | V(Int32, int32_t) \ |
| 639 | V(Uint32, uint32_t) \ |
| 640 | V(Int64, int64_t) \ |
| 641 | V(Uint64, uint64_t) \ |
| 642 | V(Float32, float) \ |
| 643 | V(Float64, double) \ |
| 644 | V(Int32x4, simd128_value_t) \ |
| 645 | V(Float32x4, simd128_value_t) \ |
| 646 | V(Float64x2, simd128_value_t) |
| 647 | |
| 648 | #define EMIT_TYPED_DATA_CASES(type, c_type) \ |
| 649 | case kTypedData##type##ArrayCid: \ |
| 650 | READ_TYPED_DATA(type, c_type); \ |
| 651 | case kExternalTypedData##type##ArrayCid: \ |
| 652 | READ_EXTERNAL_TYPED_DATA(type, c_type); \ |
| 653 | case kTypedData##type##ArrayViewCid: \ |
| 654 | READ_TYPED_DATA_VIEW(type, c_type); |
| 655 | |
| 656 | TYPED_DATA_LIST(EMIT_TYPED_DATA_CASES) |
| 657 | #undef EMIT_TYPED_DATA_CASES |
| 658 | #undef TYPED_DATA_LIST |
| 659 | #undef READ_TYPED_DATA |
| 660 | #undef READ_EXTERNAL_TYPED_DATA |
| 661 | #undef READ_TYPED_DATA_VIEW |
| 662 | |
| 663 | case kGrowableObjectArrayCid: { |
| 664 | // A GrowableObjectArray is serialized as its type arguments and |
| 665 | // length followed by its backing store. The backing store is an |
| 666 | // array with a length which might be longer than the length of |
| 667 | // the GrowableObjectArray. |
| 668 | Dart_CObject* value = GetBackRef(object_id); |
| 669 | ASSERT(value == NULL); |
| 670 | // Allocate an empty array for the GrowableObjectArray which |
| 671 | // will be updated to point to the content when the backing |
| 672 | // store has been deserialized. |
| 673 | value = AllocateDartCObjectArray(0); |
| 674 | AddBackRef(object_id, value, kIsDeserialized); |
| 675 | |
| 676 | // Read and skip the type arguments field. |
| 677 | // TODO(sjesse): Remove this when message serialization format is |
| 678 | // updated (currently type_arguments is leaked). |
| 679 | Dart_CObject* type_arguments = ReadObjectImpl(); |
| 680 | if (type_arguments != &type_arguments_marker && |
| 681 | type_arguments->type != Dart_CObject_kNull) { |
| 682 | return AllocateDartCObjectUnsupported(); |
| 683 | } |
| 684 | |
| 685 | // Read the length field. |
| 686 | intptr_t len = ReadSmiValue(); |
| 687 | |
| 688 | // Read the content of the GrowableObjectArray. |
| 689 | Dart_CObject* content = ReadObjectRef(); |
| 690 | ASSERT(content->type == Dart_CObject_kArray); |
| 691 | // Make the empty array allocated point to the backing store content. |
| 692 | value->value.as_array.length = len; |
| 693 | value->value.as_array.values = content->value.as_array.values; |
| 694 | return value; |
| 695 | } |
| 696 | default: |
| 697 | // Everything else not supported. |
| 698 | Dart_CObject* value = AllocateDartCObjectUnsupported(); |
| 699 | AddBackRef(object_id, value, kIsDeserialized); |
| 700 | return value; |
| 701 | } |
| 702 | } |
| 703 | |
| 704 | Dart_CObject* ApiMessageReader::ReadIndexedObject(intptr_t object_id) { |
| 705 | if (object_id >= kFirstTypeSnapshotId && object_id <= kLastTypeSnapshotId) { |
| 706 | // Always return dynamic type (this is only a marker). |
| 707 | return &dynamic_type_marker; |
| 708 | } |
| 709 | if (object_id >= kFirstTypeArgumentsSnapshotId && |
| 710 | object_id <= kLastTypeArgumentsSnapshotId) { |
| 711 | return &type_arguments_marker; |
| 712 | } |
| 713 | |
| 714 | intptr_t index = object_id - kMaxPredefinedObjectIds; |
| 715 | ASSERT((0 <= index) && (index < backward_references_.length())); |
| 716 | ASSERT(backward_references_[index]->reference() != NULL); |
| 717 | return backward_references_[index]->reference(); |
| 718 | } |
| 719 | |
| 720 | Dart_CObject* ApiMessageReader::ReadObject() { |
| 721 | Dart_CObject* value = ReadObjectImpl(); |
| 722 | for (intptr_t i = 0; i < backward_references_.length(); i++) { |
| 723 | if (!backward_references_[i]->is_deserialized()) { |
| 724 | ReadObjectImpl(); |
| 725 | backward_references_[i]->set_state(kIsDeserialized); |
| 726 | } |
| 727 | } |
| 728 | return value; |
| 729 | } |
| 730 | |
| 731 | Dart_CObject* ApiMessageReader::ReadObjectImpl() { |
| 732 | int64_t value64 = Read<int64_t>(); |
| 733 | if ((value64 & kSmiTagMask) == 0) { |
| 734 | int64_t untagged_value = value64 >> kSmiTagShift; |
| 735 | if ((kMinInt32 <= untagged_value) && (untagged_value <= kMaxInt32)) { |
| 736 | return AllocateDartCObjectInt32(static_cast<int32_t>(untagged_value)); |
| 737 | } else { |
| 738 | return AllocateDartCObjectInt64(untagged_value); |
| 739 | } |
| 740 | } |
| 741 | ASSERT((value64 <= kIntptrMax) && (value64 >= kIntptrMin)); |
| 742 | intptr_t value = static_cast<intptr_t>(value64); |
| 743 | if (IsVMIsolateObject(value)) { |
| 744 | return ReadVMIsolateObject(value); |
| 745 | } |
| 746 | if (SerializedHeaderTag::decode(value) == kObjectId) { |
| 747 | return ReadIndexedObject(SerializedHeaderData::decode(value)); |
| 748 | } |
| 749 | ASSERT(SerializedHeaderTag::decode(value) == kInlined); |
| 750 | |
| 751 | intptr_t object_id = SerializedHeaderData::decode(value); |
| 752 | if (object_id == kOmittedObjectId) { |
| 753 | object_id = NextAvailableObjectId(); |
| 754 | } |
| 755 | return ReadInlinedObject(object_id); |
| 756 | } |
| 757 | |
| 758 | void ApiMessageReader::AddBackRef(intptr_t id, |
| 759 | Dart_CObject* obj, |
| 760 | DeserializeState state) { |
| 761 | intptr_t index = (id - kMaxPredefinedObjectIds); |
| 762 | ASSERT(index == backward_references_.length()); |
| 763 | BackRefNode* node = AllocateBackRefNode(obj, state); |
| 764 | ASSERT(node != NULL); |
| 765 | backward_references_.Add(node); |
| 766 | } |
| 767 | |
| 768 | Dart_CObject* ApiMessageReader::GetBackRef(intptr_t id) { |
| 769 | ASSERT(id >= kMaxPredefinedObjectIds); |
| 770 | intptr_t index = (id - kMaxPredefinedObjectIds); |
| 771 | if (index < backward_references_.length()) { |
| 772 | return backward_references_[index]->reference(); |
| 773 | } |
| 774 | return NULL; |
| 775 | } |
| 776 | |
| 777 | static uint8_t* malloc_allocator(uint8_t* ptr, |
| 778 | intptr_t old_size, |
| 779 | intptr_t new_size) { |
| 780 | void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); |
| 781 | return reinterpret_cast<uint8_t*>(new_ptr); |
| 782 | } |
| 783 | |
| 784 | ApiMessageWriter::ApiMessageWriter() |
| 785 | : BaseWriter(malloc_allocator, NULL, kInitialSize), |
| 786 | object_id_(0), |
| 787 | forward_list_(NULL), |
| 788 | forward_list_length_(0), |
| 789 | forward_id_(0), |
| 790 | finalizable_data_(new MessageFinalizableData()) { |
| 791 | ASSERT(kDartCObjectTypeMask >= Dart_CObject_kNumberOfTypes - 1); |
| 792 | } |
| 793 | |
| 794 | ApiMessageWriter::~ApiMessageWriter() { |
| 795 | ::free(forward_list_); |
| 796 | delete finalizable_data_; |
| 797 | } |
| 798 | |
| 799 | NO_SANITIZE_UNDEFINED( |
| 800 | "enum" ) // TODO(https://github.com/dart-lang/sdk/issues/39427) |
| 801 | void ApiMessageWriter::MarkCObject(Dart_CObject* object, intptr_t object_id) { |
| 802 | // Mark the object as serialized by adding the object id to the |
| 803 | // upper bits of the type field in the Dart_CObject structure. Add |
| 804 | // an offset for making marking of object id 0 possible. |
| 805 | ASSERT(!IsCObjectMarked(object)); |
| 806 | intptr_t mark_value = object_id + kDartCObjectMarkOffset; |
| 807 | object->type = static_cast<Dart_CObject_Type>( |
| 808 | ((mark_value) << kDartCObjectTypeBits) | object->type); |
| 809 | } |
| 810 | |
| 811 | NO_SANITIZE_UNDEFINED( |
| 812 | "enum" ) // TODO(https://github.com/dart-lang/sdk/issues/39427) |
| 813 | void ApiMessageWriter::UnmarkCObject(Dart_CObject* object) { |
| 814 | ASSERT(IsCObjectMarked(object)); |
| 815 | object->type = |
| 816 | static_cast<Dart_CObject_Type>(object->type & kDartCObjectTypeMask); |
| 817 | } |
| 818 | |
| 819 | NO_SANITIZE_UNDEFINED( |
| 820 | "enum" ) // TODO(https://github.com/dart-lang/sdk/issues/39427) |
| 821 | bool ApiMessageWriter::IsCObjectMarked(Dart_CObject* object) { |
| 822 | return (object->type & kDartCObjectMarkMask) != 0; |
| 823 | } |
| 824 | |
| 825 | NO_SANITIZE_UNDEFINED( |
| 826 | "enum" ) // TODO(https://github.com/dart-lang/sdk/issues/39427) |
| 827 | intptr_t ApiMessageWriter::GetMarkedCObjectMark(Dart_CObject* object) { |
| 828 | ASSERT(IsCObjectMarked(object)); |
| 829 | intptr_t mark_value = |
| 830 | ((object->type & kDartCObjectMarkMask) >> kDartCObjectTypeBits); |
| 831 | // An offset was added to object id for making marking object id 0 possible. |
| 832 | return mark_value - kDartCObjectMarkOffset; |
| 833 | } |
| 834 | |
| 835 | void ApiMessageWriter::UnmarkAllCObjects(Dart_CObject* object) { |
| 836 | if (!IsCObjectMarked(object)) return; |
| 837 | UnmarkCObject(object); |
| 838 | if (object->type == Dart_CObject_kArray) { |
| 839 | for (int i = 0; i < object->value.as_array.length; i++) { |
| 840 | Dart_CObject* element = object->value.as_array.values[i]; |
| 841 | UnmarkAllCObjects(element); |
| 842 | } |
| 843 | } |
| 844 | } |
| 845 | |
| 846 | void ApiMessageWriter::AddToForwardList(Dart_CObject* object) { |
| 847 | if (forward_id_ >= forward_list_length_) { |
| 848 | void* new_list = NULL; |
| 849 | if (forward_list_length_ == 0) { |
| 850 | forward_list_length_ = 4; |
| 851 | intptr_t new_size = forward_list_length_ * sizeof(object); |
| 852 | new_list = ::malloc(new_size); |
| 853 | } else { |
| 854 | forward_list_length_ *= 2; |
| 855 | intptr_t new_size = (forward_list_length_ * sizeof(object)); |
| 856 | new_list = ::realloc(forward_list_, new_size); |
| 857 | } |
| 858 | ASSERT(new_list != NULL); |
| 859 | forward_list_ = reinterpret_cast<Dart_CObject**>(new_list); |
| 860 | } |
| 861 | forward_list_[forward_id_] = object; |
| 862 | forward_id_ += 1; |
| 863 | } |
| 864 | |
| 865 | void ApiMessageWriter::WriteSmi(int64_t value) { |
| 866 | ASSERT(Smi::IsValid(value)); |
| 867 | Write<ObjectPtr>(Smi::New(static_cast<intptr_t>(value))); |
| 868 | } |
| 869 | |
| 870 | void ApiMessageWriter::WriteNullObject() { |
| 871 | WriteVMIsolateObject(kNullObject); |
| 872 | } |
| 873 | |
| 874 | void ApiMessageWriter::WriteMint(Dart_CObject* object, int64_t value) { |
| 875 | ASSERT(!Smi::IsValid(value)); |
| 876 | // Write out the serialization header value for mint object. |
| 877 | WriteInlinedHeader(object); |
| 878 | // Write out the class and tags information. |
| 879 | WriteIndexedObject(kMintCid); |
| 880 | WriteTags(0); |
| 881 | // Write the 64-bit value. |
| 882 | Write<int64_t>(value); |
| 883 | } |
| 884 | |
| 885 | void ApiMessageWriter::WriteInt32(Dart_CObject* object) { |
| 886 | int64_t value = object->value.as_int32; |
| 887 | if (Smi::IsValid(value)) { |
| 888 | WriteSmi(value); |
| 889 | } else { |
| 890 | WriteMint(object, value); |
| 891 | } |
| 892 | } |
| 893 | |
| 894 | void ApiMessageWriter::WriteInt64(Dart_CObject* object) { |
| 895 | int64_t value = object->value.as_int64; |
| 896 | if (Smi::IsValid(value)) { |
| 897 | WriteSmi(value); |
| 898 | } else { |
| 899 | WriteMint(object, value); |
| 900 | } |
| 901 | } |
| 902 | |
| 903 | void ApiMessageWriter::(Dart_CObject* object) { |
| 904 | // Write out the serialization header value for this object. |
| 905 | WriteInlinedObjectHeader(kMaxPredefinedObjectIds + object_id_); |
| 906 | // Mark object with its object id. |
| 907 | MarkCObject(object, object_id_); |
| 908 | // Advance object id. |
| 909 | object_id_++; |
| 910 | } |
| 911 | |
| 912 | bool ApiMessageWriter::WriteCObject(Dart_CObject* object) { |
| 913 | if (IsCObjectMarked(object)) { |
| 914 | intptr_t object_id = GetMarkedCObjectMark(object); |
| 915 | WriteIndexedObject(kMaxPredefinedObjectIds + object_id); |
| 916 | return true; |
| 917 | } |
| 918 | |
| 919 | Dart_CObject_Type type = object->type; |
| 920 | if (type == Dart_CObject_kArray) { |
| 921 | const intptr_t array_length = object->value.as_array.length; |
| 922 | if (!Array::IsValidLength(array_length)) { |
| 923 | return false; |
| 924 | } |
| 925 | |
| 926 | // Write out the serialization header value for this object. |
| 927 | WriteInlinedHeader(object); |
| 928 | // Write out the class and tags information. |
| 929 | WriteIndexedObject(kArrayCid); |
| 930 | WriteTags(0); |
| 931 | // Write out the length information. |
| 932 | WriteSmi(array_length); |
| 933 | // Write out the type arguments. |
| 934 | WriteNullObject(); |
| 935 | // Write out array elements. |
| 936 | for (int i = 0; i < array_length; i++) { |
| 937 | bool success = WriteCObjectRef(object->value.as_array.values[i]); |
| 938 | if (!success) return false; |
| 939 | } |
| 940 | return true; |
| 941 | } |
| 942 | return WriteCObjectInlined(object, type); |
| 943 | } |
| 944 | |
| 945 | bool ApiMessageWriter::WriteCObjectRef(Dart_CObject* object) { |
| 946 | if (IsCObjectMarked(object)) { |
| 947 | intptr_t object_id = GetMarkedCObjectMark(object); |
| 948 | WriteIndexedObject(kMaxPredefinedObjectIds + object_id); |
| 949 | return true; |
| 950 | } |
| 951 | |
| 952 | Dart_CObject_Type type = object->type; |
| 953 | if (type == Dart_CObject_kArray) { |
| 954 | const intptr_t array_length = object->value.as_array.length; |
| 955 | if (!Array::IsValidLength(array_length)) { |
| 956 | return false; |
| 957 | } |
| 958 | // Write out the serialization header value for this object. |
| 959 | WriteInlinedHeader(object); |
| 960 | // Write out the class information. |
| 961 | WriteIndexedObject(kArrayCid); |
| 962 | WriteTags(0); |
| 963 | // Write out the length information. |
| 964 | WriteSmi(array_length); |
| 965 | // Add object to forward list so that this object is serialized later. |
| 966 | AddToForwardList(object); |
| 967 | return true; |
| 968 | } |
| 969 | return WriteCObjectInlined(object, type); |
| 970 | } |
| 971 | |
| 972 | NO_SANITIZE_UNDEFINED( |
| 973 | "enum" ) // TODO(https://github.com/dart-lang/sdk/issues/39427) |
| 974 | bool ApiMessageWriter::WriteForwardedCObject(Dart_CObject* object) { |
| 975 | ASSERT(IsCObjectMarked(object)); |
| 976 | Dart_CObject_Type type = |
| 977 | static_cast<Dart_CObject_Type>(object->type & kDartCObjectTypeMask); |
| 978 | ASSERT(type == Dart_CObject_kArray); |
| 979 | const intptr_t array_length = object->value.as_array.length; |
| 980 | if (!Array::IsValidLength(array_length)) { |
| 981 | return false; |
| 982 | } |
| 983 | |
| 984 | // Write out the serialization header value for this object. |
| 985 | intptr_t object_id = GetMarkedCObjectMark(object); |
| 986 | WriteInlinedObjectHeader(kMaxPredefinedObjectIds + object_id); |
| 987 | // Write out the class and tags information. |
| 988 | WriteIndexedObject(kArrayCid); |
| 989 | WriteTags(0); |
| 990 | // Write out the length information. |
| 991 | WriteSmi(array_length); |
| 992 | // Write out the type arguments. |
| 993 | WriteNullObject(); |
| 994 | // Write out array elements. |
| 995 | for (int i = 0; i < array_length; i++) { |
| 996 | bool success = WriteCObjectRef(object->value.as_array.values[i]); |
| 997 | if (!success) return false; |
| 998 | } |
| 999 | return true; |
| 1000 | } |
| 1001 | |
| 1002 | bool ApiMessageWriter::WriteCObjectInlined(Dart_CObject* object, |
| 1003 | Dart_CObject_Type type) { |
| 1004 | switch (type) { |
| 1005 | case Dart_CObject_kNull: |
| 1006 | WriteNullObject(); |
| 1007 | break; |
| 1008 | case Dart_CObject_kBool: |
| 1009 | if (object->value.as_bool) { |
| 1010 | WriteVMIsolateObject(kTrueValue); |
| 1011 | } else { |
| 1012 | WriteVMIsolateObject(kFalseValue); |
| 1013 | } |
| 1014 | break; |
| 1015 | case Dart_CObject_kInt32: |
| 1016 | WriteInt32(object); |
| 1017 | break; |
| 1018 | case Dart_CObject_kInt64: |
| 1019 | WriteInt64(object); |
| 1020 | break; |
| 1021 | case Dart_CObject_kDouble: |
| 1022 | WriteVMIsolateObject(kDoubleObject); |
| 1023 | WriteDouble(object->value.as_double); |
| 1024 | break; |
| 1025 | case Dart_CObject_kString: { |
| 1026 | const uint8_t* utf8_str = |
| 1027 | reinterpret_cast<const uint8_t*>(object->value.as_string); |
| 1028 | intptr_t utf8_len = strlen(object->value.as_string); |
| 1029 | if (!Utf8::IsValid(utf8_str, utf8_len)) { |
| 1030 | return false; |
| 1031 | } |
| 1032 | |
| 1033 | Utf8::Type type = Utf8::kLatin1; |
| 1034 | intptr_t len = Utf8::CodeUnitCount(utf8_str, utf8_len, &type); |
| 1035 | if (len > String::kMaxElements) { |
| 1036 | return false; |
| 1037 | } |
| 1038 | |
| 1039 | // Write out the serialization header value for this object. |
| 1040 | WriteInlinedHeader(object); |
| 1041 | // Write out the class and tags information. |
| 1042 | WriteIndexedObject(type == Utf8::kLatin1 ? kOneByteStringCid |
| 1043 | : kTwoByteStringCid); |
| 1044 | WriteTags(0); |
| 1045 | // Write string length and content. |
| 1046 | WriteSmi(len); |
| 1047 | if (type == Utf8::kLatin1) { |
| 1048 | uint8_t* latin1_str = |
| 1049 | reinterpret_cast<uint8_t*>(::malloc(len * sizeof(uint8_t))); |
| 1050 | bool success = |
| 1051 | Utf8::DecodeToLatin1(utf8_str, utf8_len, latin1_str, len); |
| 1052 | ASSERT(success); |
| 1053 | for (intptr_t i = 0; i < len; i++) { |
| 1054 | Write<uint8_t>(latin1_str[i]); |
| 1055 | } |
| 1056 | ::free(latin1_str); |
| 1057 | } else { |
| 1058 | uint16_t* utf16_str = |
| 1059 | reinterpret_cast<uint16_t*>(::malloc(len * sizeof(uint16_t))); |
| 1060 | bool success = Utf8::DecodeToUTF16(utf8_str, utf8_len, utf16_str, len); |
| 1061 | ASSERT(success); |
| 1062 | for (intptr_t i = 0; i < len; i++) { |
| 1063 | Write<uint16_t>(utf16_str[i]); |
| 1064 | } |
| 1065 | ::free(utf16_str); |
| 1066 | } |
| 1067 | break; |
| 1068 | } |
| 1069 | case Dart_CObject_kTypedData: { |
| 1070 | // Write out the serialization header value for this object. |
| 1071 | WriteInlinedHeader(object); |
| 1072 | // Write out the class and tags information. |
| 1073 | intptr_t class_id; |
| 1074 | switch (object->value.as_typed_data.type) { |
| 1075 | case Dart_TypedData_kInt8: |
| 1076 | class_id = kTypedDataInt8ArrayCid; |
| 1077 | break; |
| 1078 | case Dart_TypedData_kUint8: |
| 1079 | class_id = kTypedDataUint8ArrayCid; |
| 1080 | break; |
| 1081 | case Dart_TypedData_kUint32: |
| 1082 | class_id = kTypedDataUint32ArrayCid; |
| 1083 | break; |
| 1084 | default: |
| 1085 | class_id = kTypedDataUint8ArrayCid; |
| 1086 | UNIMPLEMENTED(); |
| 1087 | } |
| 1088 | |
| 1089 | intptr_t len = object->value.as_typed_data.length; |
| 1090 | if (len < 0 || len > TypedData::MaxElements(class_id)) { |
| 1091 | return false; |
| 1092 | } |
| 1093 | |
| 1094 | WriteIndexedObject(class_id); |
| 1095 | WriteTags(0); |
| 1096 | WriteSmi(len); |
| 1097 | switch (class_id) { |
| 1098 | case kTypedDataInt8ArrayCid: |
| 1099 | case kTypedDataUint8ArrayCid: { |
| 1100 | uint8_t* bytes = object->value.as_typed_data.values; |
| 1101 | Align(Zone::kAlignment); |
| 1102 | WriteBytes(bytes, len); |
| 1103 | break; |
| 1104 | } |
| 1105 | case kTypedDataUint32ArrayCid: { |
| 1106 | uint8_t* bytes = object->value.as_typed_data.values; |
| 1107 | Align(Zone::kAlignment); |
| 1108 | WriteBytes(bytes, len * sizeof(uint32_t)); |
| 1109 | break; |
| 1110 | } |
| 1111 | default: |
| 1112 | UNIMPLEMENTED(); |
| 1113 | } |
| 1114 | break; |
| 1115 | } |
| 1116 | case Dart_CObject_kExternalTypedData: { |
| 1117 | // TODO(ager): we are writing C pointers into the message in |
| 1118 | // order to post external arrays through ports. We need to make |
| 1119 | // sure that messages containing pointers can never be posted |
| 1120 | // to other processes. |
| 1121 | |
| 1122 | // Write out serialization header value for this object. |
| 1123 | WriteInlinedHeader(object); |
| 1124 | // Write out the class and tag information. |
| 1125 | WriteIndexedObject(kExternalTypedDataUint8ArrayCid); |
| 1126 | WriteTags(0); |
| 1127 | intptr_t length = object->value.as_external_typed_data.length; |
| 1128 | if (length < 0 || length > ExternalTypedData::MaxElements( |
| 1129 | kExternalTypedDataUint8ArrayCid)) { |
| 1130 | return false; |
| 1131 | } |
| 1132 | uint8_t* data = object->value.as_external_typed_data.data; |
| 1133 | void* peer = object->value.as_external_typed_data.peer; |
| 1134 | Dart_WeakPersistentHandleFinalizer callback = |
| 1135 | object->value.as_external_typed_data.callback; |
| 1136 | if (callback == NULL) { |
| 1137 | return false; |
| 1138 | } |
| 1139 | WriteSmi(length); |
| 1140 | finalizable_data_->Put(length, reinterpret_cast<void*>(data), peer, |
| 1141 | callback); |
| 1142 | break; |
| 1143 | } |
| 1144 | case Dart_CObject_kSendPort: { |
| 1145 | WriteInlinedHeader(object); |
| 1146 | WriteIndexedObject(kSendPortCid); |
| 1147 | WriteTags(0); |
| 1148 | Write<int64_t>(object->value.as_send_port.id); |
| 1149 | Write<uint64_t>(object->value.as_send_port.origin_id); |
| 1150 | break; |
| 1151 | } |
| 1152 | case Dart_CObject_kCapability: { |
| 1153 | WriteInlinedHeader(object); |
| 1154 | WriteIndexedObject(kCapabilityCid); |
| 1155 | WriteTags(0); |
| 1156 | Write<uint64_t>(object->value.as_capability.id); |
| 1157 | break; |
| 1158 | } |
| 1159 | default: |
| 1160 | FATAL1("Unexpected Dart_CObject_Type %d\n" , type); |
| 1161 | } |
| 1162 | |
| 1163 | return true; |
| 1164 | } |
| 1165 | |
| 1166 | std::unique_ptr<Message> ApiMessageWriter::WriteCMessage( |
| 1167 | Dart_CObject* object, |
| 1168 | Dart_Port dest_port, |
| 1169 | Message::Priority priority) { |
| 1170 | bool success = WriteCObject(object); |
| 1171 | if (!success) { |
| 1172 | UnmarkAllCObjects(object); |
| 1173 | free(buffer()); |
| 1174 | return nullptr; |
| 1175 | } |
| 1176 | |
| 1177 | // Write out all objects that were added to the forward list and have |
| 1178 | // not been serialized yet. These would typically be fields of arrays. |
| 1179 | // NOTE: The forward list might grow as we process the list. |
| 1180 | for (intptr_t i = 0; i < forward_id_; i++) { |
| 1181 | success = WriteForwardedCObject(forward_list_[i]); |
| 1182 | if (!success) { |
| 1183 | UnmarkAllCObjects(object); |
| 1184 | free(buffer()); |
| 1185 | return nullptr; |
| 1186 | } |
| 1187 | } |
| 1188 | |
| 1189 | UnmarkAllCObjects(object); |
| 1190 | MessageFinalizableData* finalizable_data = finalizable_data_; |
| 1191 | finalizable_data_ = NULL; |
| 1192 | return Message::New(dest_port, buffer(), BytesWritten(), finalizable_data, |
| 1193 | priority); |
| 1194 | } |
| 1195 | |
| 1196 | } // namespace dart |
| 1197 | |