| Index: runtime/lib/typeddata.cc
|
| diff --git a/runtime/lib/typeddata.cc b/runtime/lib/typeddata.cc
|
| deleted file mode 100644
|
| index 4a47d7123d6bc348aea504ef925ee2e9e594fd31..0000000000000000000000000000000000000000
|
| --- a/runtime/lib/typeddata.cc
|
| +++ /dev/null
|
| @@ -1,443 +0,0 @@
|
| -// Copyright (c) 2013, 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.
|
| -
|
| -#include "vm/bootstrap_natives.h"
|
| -
|
| -#include "include/dart_api.h"
|
| -
|
| -#include "vm/bigint_operations.h"
|
| -#include "vm/exceptions.h"
|
| -#include "vm/native_entry.h"
|
| -#include "vm/object.h"
|
| -
|
| -namespace dart {
|
| -
|
| -// TypedData.
|
| -
|
| -// Checks to see if offset_in_bytes is in the range.
|
| -static bool RangeCheck(intptr_t offset_in_bytes, intptr_t length_in_bytes) {
|
| - return ((offset_in_bytes >= 0) &&
|
| - (length_in_bytes > 0) &&
|
| - (offset_in_bytes < length_in_bytes));
|
| -}
|
| -
|
| -
|
| -// Checks to see if offsetInBytes + num_bytes is in the range.
|
| -static void SetRangeCheck(intptr_t offset_in_bytes,
|
| - intptr_t num_bytes,
|
| - intptr_t length_in_bytes,
|
| - intptr_t element_size_in_bytes) {
|
| - if (!Utils::RangeCheck(offset_in_bytes, num_bytes, length_in_bytes)) {
|
| - const String& error = String::Handle(String::NewFormatted(
|
| - "index (%"Pd") must be in the range [0..%"Pd")",
|
| - (offset_in_bytes / element_size_in_bytes),
|
| - (length_in_bytes / element_size_in_bytes)));
|
| - const Array& args = Array::Handle(Array::New(1));
|
| - args.SetAt(0, error);
|
| - Exceptions::ThrowByType(Exceptions::kRange, args);
|
| - }
|
| -}
|
| -
|
| -
|
| -// Checks to see if a length will not result in an OOM error.
|
| -static void LengthCheck(intptr_t len, intptr_t max) {
|
| - ASSERT(len >= 0);
|
| - if (len > max) {
|
| - const String& error = String::Handle(String::NewFormatted(
|
| - "insufficient memory to allocate a TypedData object of length (%"Pd")",
|
| - len));
|
| - const Array& args = Array::Handle(Array::New(1));
|
| - args.SetAt(0, error);
|
| - Exceptions::ThrowByType(Exceptions::kOutOfMemory, args);
|
| - }
|
| -}
|
| -
|
| -
|
| -static void PeerFinalizer(Dart_Handle handle, void* peer) {
|
| - Dart_DeletePersistentHandle(handle);
|
| - OS::AlignedFree(peer);
|
| -}
|
| -
|
| -
|
| -DEFINE_NATIVE_ENTRY(TypedData_length, 1) {
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
|
| - if (instance.IsTypedData()) {
|
| - const TypedData& array = TypedData::Cast(instance);
|
| - return Smi::New(array.Length());
|
| - }
|
| - if (instance.IsExternalTypedData()) {
|
| - const ExternalTypedData& array = ExternalTypedData::Cast(instance);
|
| - return Smi::New(array.Length());
|
| - }
|
| - const String& error = String::Handle(String::NewFormatted(
|
| - "Expected a TypedData object but found %s", instance.ToCString()));
|
| - const Array& args = Array::Handle(Array::New(1));
|
| - args.SetAt(0, error);
|
| - Exceptions::ThrowByType(Exceptions::kArgument, args);
|
| - return Integer::null();
|
| -}
|
| -
|
| -template <typename DstType, typename SrcType>
|
| -static RawBool* CopyData(const Instance& dst, const Instance& src,
|
| - const Smi& dst_start, const Smi& src_start,
|
| - const Smi& length) {
|
| - const DstType& dst_array = DstType::Cast(dst);
|
| - const SrcType& src_array = SrcType::Cast(src);
|
| - intptr_t element_size_in_bytes = dst_array.ElementSizeInBytes();
|
| - intptr_t dst_offset_in_bytes = dst_start.Value() * element_size_in_bytes;
|
| - intptr_t src_offset_in_bytes = src_start.Value() * element_size_in_bytes;
|
| - intptr_t length_in_bytes = length.Value() * element_size_in_bytes;
|
| - if (dst_array.ElementType() != src_array.ElementType()) {
|
| - return Bool::False().raw();
|
| - }
|
| - SetRangeCheck(src_offset_in_bytes,
|
| - length_in_bytes,
|
| - src_array.LengthInBytes(),
|
| - element_size_in_bytes);
|
| - SetRangeCheck(dst_offset_in_bytes,
|
| - length_in_bytes,
|
| - dst_array.LengthInBytes(),
|
| - element_size_in_bytes);
|
| - TypedData::Copy<DstType, SrcType>(dst_array, dst_offset_in_bytes,
|
| - src_array, src_offset_in_bytes,
|
| - length_in_bytes);
|
| - return Bool::True().raw();
|
| -}
|
| -
|
| -DEFINE_NATIVE_ENTRY(TypedData_setRange, 5) {
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Instance, dst, arguments->NativeArgAt(0));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Smi, dst_start, arguments->NativeArgAt(1));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(2));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Instance, src, arguments->NativeArgAt(3));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Smi, src_start, arguments->NativeArgAt(4));
|
| -
|
| - if (length.Value() < 0) {
|
| - const String& error = String::Handle(String::NewFormatted(
|
| - "length (%"Pd") must be non-negative", length.Value()));
|
| - const Array& args = Array::Handle(Array::New(1));
|
| - args.SetAt(0, error);
|
| - Exceptions::ThrowByType(Exceptions::kArgument, args);
|
| - }
|
| - if (dst.IsTypedData()) {
|
| - if (src.IsTypedData()) {
|
| - return CopyData<TypedData, TypedData>(
|
| - dst, src, dst_start, src_start, length);
|
| - } else if (src.IsExternalTypedData()) {
|
| - return CopyData<TypedData, ExternalTypedData>(
|
| - dst, src, dst_start, src_start, length);
|
| - }
|
| - } else if (dst.IsExternalTypedData()) {
|
| - if (src.IsTypedData()) {
|
| - return CopyData<ExternalTypedData, TypedData>(
|
| - dst, src, dst_start, src_start, length);
|
| - } else if (src.IsExternalTypedData()) {
|
| - return CopyData<ExternalTypedData, ExternalTypedData>(
|
| - dst, src, dst_start, src_start, length);
|
| - }
|
| - }
|
| - return Bool::False().raw();
|
| -}
|
| -
|
| -
|
| -// We check the length parameter against a possible maximum length for the
|
| -// array based on available physical addressable memory on the system. The
|
| -// maximum possible length is a scaled value of kSmiMax which is set up based
|
| -// on whether the underlying architecture is 32-bit or 64-bit.
|
| -#define TYPED_DATA_NEW(name) \
|
| -DEFINE_NATIVE_ENTRY(TypedData_##name##_new, 1) { \
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(0)); \
|
| - intptr_t cid = kTypedData##name##Cid; \
|
| - intptr_t len = length.Value(); \
|
| - intptr_t max = TypedData::MaxElements(cid); \
|
| - LengthCheck(len, max); \
|
| - return TypedData::New(cid, len); \
|
| -} \
|
| -
|
| -
|
| -// We check the length parameter against a possible maximum length for the
|
| -// array based on available physical addressable memory on the system. The
|
| -// maximum possible length is a scaled value of kSmiMax which is set up based
|
| -// on whether the underlying architecture is 32-bit or 64-bit.
|
| -#define EXT_TYPED_DATA_NEW(name) \
|
| -DEFINE_NATIVE_ENTRY(ExternalTypedData_##name##_new, 1) { \
|
| - const int kAlignment = 16; \
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(0)); \
|
| - intptr_t cid = kExternalTypedData##name##Cid; \
|
| - intptr_t len = length.Value(); \
|
| - intptr_t max = ExternalTypedData::MaxElements(cid); \
|
| - LengthCheck(len, max); \
|
| - intptr_t len_bytes = len * ExternalTypedData::ElementSizeInBytes(cid); \
|
| - uint8_t* data = OS::AllocateAlignedArray<uint8_t>(len_bytes, kAlignment); \
|
| - const ExternalTypedData& obj = \
|
| - ExternalTypedData::Handle(ExternalTypedData::New(cid, data, len)); \
|
| - obj.AddFinalizer(data, PeerFinalizer); \
|
| - return obj.raw(); \
|
| -} \
|
| -
|
| -
|
| -#define TYPED_DATA_NEW_NATIVE(name) \
|
| - TYPED_DATA_NEW(name) \
|
| - EXT_TYPED_DATA_NEW(name) \
|
| -
|
| -
|
| -CLASS_LIST_TYPED_DATA(TYPED_DATA_NEW_NATIVE)
|
| -
|
| -#define TYPED_DATA_GETTER(getter, object) \
|
| -DEFINE_NATIVE_ENTRY(TypedData_##getter, 2) { \
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \
|
| - if (instance.IsTypedData()) { \
|
| - const TypedData& array = TypedData::Cast(instance); \
|
| - ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
|
| - return object::New(array.getter(offsetInBytes.Value())); \
|
| - } \
|
| - if (instance.IsExternalTypedData()) { \
|
| - const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
|
| - ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
|
| - return object::New(array.getter(offsetInBytes.Value())); \
|
| - } \
|
| - const String& error = String::Handle(String::NewFormatted( \
|
| - "Expected a TypedData object but found %s", instance.ToCString())); \
|
| - const Array& args = Array::Handle(Array::New(1)); \
|
| - args.SetAt(0, error); \
|
| - Exceptions::ThrowByType(Exceptions::kArgument, args); \
|
| - return object::null(); \
|
| -} \
|
| -
|
| -
|
| -#define TYPED_DATA_SETTER(setter, object, get_object_value) \
|
| -DEFINE_NATIVE_ENTRY(TypedData_##setter, 3) { \
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \
|
| - GET_NON_NULL_NATIVE_ARGUMENT(object, value, arguments->NativeArgAt(2)); \
|
| - if (instance.IsTypedData()) { \
|
| - const TypedData& array = TypedData::Cast(instance); \
|
| - ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
|
| - array.setter(offsetInBytes.Value(), value.get_object_value()); \
|
| - } else if (instance.IsExternalTypedData()) { \
|
| - const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
|
| - ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
|
| - array.setter(offsetInBytes.Value(), value.get_object_value()); \
|
| - } else { \
|
| - const String& error = String::Handle(String::NewFormatted( \
|
| - "Expected a TypedData object but found %s", instance.ToCString())); \
|
| - const Array& args = Array::Handle(Array::New(1)); \
|
| - args.SetAt(0, error); \
|
| - Exceptions::ThrowByType(Exceptions::kArgument, args); \
|
| - } \
|
| - return Object::null(); \
|
| -}
|
| -
|
| -
|
| -#define TYPED_DATA_UINT64_GETTER(getter, object) \
|
| -DEFINE_NATIVE_ENTRY(TypedData_##getter, 2) { \
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \
|
| - uint64_t value = 0; \
|
| - if (instance.IsTypedData()) { \
|
| - const TypedData& array = TypedData::Cast(instance); \
|
| - ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
|
| - value = array.getter(offsetInBytes.Value()); \
|
| - } else if (instance.IsExternalTypedData()) { \
|
| - const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
|
| - ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
|
| - value = array.getter(offsetInBytes.Value()); \
|
| - } else { \
|
| - const String& error = String::Handle(String::NewFormatted( \
|
| - "Expected a TypedData object but found %s", instance.ToCString())); \
|
| - const Array& args = Array::Handle(Array::New(1)); \
|
| - args.SetAt(0, error); \
|
| - Exceptions::ThrowByType(Exceptions::kArgument, args); \
|
| - } \
|
| - Integer& result = Integer::Handle(); \
|
| - if (value > static_cast<uint64_t>(Mint::kMaxValue)) { \
|
| - result = BigintOperations::NewFromUint64(value); \
|
| - } else if (value > static_cast<uint64_t>(Smi::kMaxValue)) { \
|
| - result = Mint::New(value); \
|
| - } else { \
|
| - result = Smi::New(value); \
|
| - } \
|
| - return result.raw(); \
|
| -} \
|
| -
|
| -
|
| -// TODO(asiva): Consider truncating the bigint value if it does not fit into
|
| -// a uint64_t value (see ASSERT(BigintOperations::FitsIntoUint64(bigint))).
|
| -#define TYPED_DATA_UINT64_SETTER(setter, object) \
|
| -DEFINE_NATIVE_ENTRY(TypedData_##setter, 3) { \
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0)); \
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes, arguments->NativeArgAt(1)); \
|
| - GET_NON_NULL_NATIVE_ARGUMENT(object, value, arguments->NativeArgAt(2)); \
|
| - uint64_t object_value; \
|
| - if (value.IsBigint()) { \
|
| - const Bigint& bigint = Bigint::Cast(value); \
|
| - ASSERT(BigintOperations::FitsIntoUint64(bigint)); \
|
| - object_value = BigintOperations::AbsToUint64(bigint); \
|
| - } else { \
|
| - ASSERT(value.IsMint() || value.IsSmi()); \
|
| - object_value = value.AsInt64Value(); \
|
| - } \
|
| - if (instance.IsTypedData()) { \
|
| - const TypedData& array = TypedData::Cast(instance); \
|
| - ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
|
| - array.setter(offsetInBytes.Value(), object_value); \
|
| - } else if (instance.IsExternalTypedData()) { \
|
| - const ExternalTypedData& array = ExternalTypedData::Cast(instance); \
|
| - ASSERT(RangeCheck(offsetInBytes.Value(), array.LengthInBytes())); \
|
| - array.setter(offsetInBytes.Value(), object_value); \
|
| - } else { \
|
| - const String& error = String::Handle(String::NewFormatted( \
|
| - "Expected a TypedData object but found %s", instance.ToCString())); \
|
| - const Array& args = Array::Handle(Array::New(1)); \
|
| - args.SetAt(0, error); \
|
| - Exceptions::ThrowByType(Exceptions::kArgument, args); \
|
| - } \
|
| - return Object::null(); \
|
| -}
|
| -
|
| -
|
| -#define TYPED_DATA_NATIVES(getter, setter, object, get_object_value) \
|
| - TYPED_DATA_GETTER(getter, object) \
|
| - TYPED_DATA_SETTER(setter, object, get_object_value) \
|
| -
|
| -
|
| -#define TYPED_DATA_UINT64_NATIVES(getter, setter, object) \
|
| - TYPED_DATA_UINT64_GETTER(getter, object) \
|
| - TYPED_DATA_UINT64_SETTER(setter, object) \
|
| -
|
| -
|
| -TYPED_DATA_NATIVES(GetInt8, SetInt8, Smi, Value)
|
| -TYPED_DATA_NATIVES(GetUint8, SetUint8, Smi, Value)
|
| -TYPED_DATA_NATIVES(GetInt16, SetInt16, Smi, Value)
|
| -TYPED_DATA_NATIVES(GetUint16, SetUint16, Smi, Value)
|
| -TYPED_DATA_NATIVES(GetInt32, SetInt32, Integer, AsInt64Value)
|
| -TYPED_DATA_NATIVES(GetUint32, SetUint32, Integer, AsInt64Value)
|
| -TYPED_DATA_NATIVES(GetInt64, SetInt64, Integer, AsInt64Value)
|
| -TYPED_DATA_UINT64_NATIVES(GetUint64, SetUint64, Integer)
|
| -TYPED_DATA_NATIVES(GetFloat32, SetFloat32, Double, value)
|
| -TYPED_DATA_NATIVES(GetFloat64, SetFloat64, Double, value)
|
| -TYPED_DATA_NATIVES(GetFloat32x4, SetFloat32x4, Float32x4, value)
|
| -
|
| -
|
| -DEFINE_NATIVE_ENTRY(ByteData_ToEndianInt16, 2) {
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Smi, host_value, arguments->NativeArgAt(0));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
|
| - int16_t value = host_value.Value();
|
| - if (little_endian.value()) {
|
| - value = Utils::HostToLittleEndian16(value);
|
| - } else {
|
| - value = Utils::HostToBigEndian16(value);
|
| - }
|
| - return Smi::New(value);
|
| -}
|
| -
|
| -
|
| -DEFINE_NATIVE_ENTRY(ByteData_ToEndianUint16, 2) {
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Smi, host_value, arguments->NativeArgAt(0));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
|
| - uint16_t value = host_value.Value();
|
| - if (little_endian.value()) {
|
| - return Smi::New(Utils::HostToLittleEndian16(value));
|
| - }
|
| - return Smi::New(Utils::HostToBigEndian16(value));
|
| -}
|
| -
|
| -
|
| -DEFINE_NATIVE_ENTRY(ByteData_ToEndianInt32, 2) {
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Integer, host_value, arguments->NativeArgAt(0));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
|
| - ASSERT(host_value.AsInt64Value() <= kMaxInt32);
|
| - int32_t value = host_value.AsInt64Value();
|
| - if (little_endian.value()) {
|
| - value = Utils::HostToLittleEndian32(value);
|
| - } else {
|
| - value = Utils::HostToBigEndian32(value);
|
| - }
|
| - return Integer::New(value);
|
| -}
|
| -
|
| -
|
| -DEFINE_NATIVE_ENTRY(ByteData_ToEndianUint32, 2) {
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Integer, host_value, arguments->NativeArgAt(0));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
|
| - ASSERT(host_value.AsInt64Value() <= kMaxUint32);
|
| - uint32_t value = host_value.AsInt64Value();
|
| - if (little_endian.value()) {
|
| - value = Utils::HostToLittleEndian32(value);
|
| - } else {
|
| - value = Utils::HostToBigEndian32(value);
|
| - }
|
| - return Integer::New(value);
|
| -}
|
| -
|
| -
|
| -DEFINE_NATIVE_ENTRY(ByteData_ToEndianInt64, 2) {
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Integer, host_value, arguments->NativeArgAt(0));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
|
| - int64_t value = host_value.AsInt64Value();
|
| - if (little_endian.value()) {
|
| - value = Utils::HostToLittleEndian64(value);
|
| - } else {
|
| - value = Utils::HostToBigEndian64(value);
|
| - }
|
| - return Integer::New(value);
|
| -}
|
| -
|
| -
|
| -DEFINE_NATIVE_ENTRY(ByteData_ToEndianUint64, 2) {
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Integer, host_value, arguments->NativeArgAt(0));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
|
| - uint64_t value;
|
| - if (host_value.IsBigint()) {
|
| - const Bigint& bigint = Bigint::Cast(host_value);
|
| - ASSERT(BigintOperations::FitsIntoUint64(bigint));
|
| - value = BigintOperations::AbsToUint64(bigint);
|
| - } else {
|
| - ASSERT(host_value.IsMint() || host_value.IsSmi());
|
| - value = host_value.AsInt64Value();
|
| - }
|
| - if (little_endian.value()) {
|
| - value = Utils::HostToLittleEndian64(value);
|
| - } else {
|
| - value = Utils::HostToBigEndian64(value);
|
| - }
|
| - if (value > static_cast<uint64_t>(Mint::kMaxValue)) {
|
| - return BigintOperations::NewFromUint64(value);
|
| - } else if (value > static_cast<uint64_t>(Smi::kMaxValue)) {
|
| - return Mint::New(value);
|
| - }
|
| - return Smi::New(value);
|
| -}
|
| -
|
| -
|
| -DEFINE_NATIVE_ENTRY(ByteData_ToEndianFloat32, 2) {
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Double, host_value, arguments->NativeArgAt(0));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
|
| - float value = host_value.value();
|
| - if (little_endian.value()) {
|
| - value = bit_cast<float>(
|
| - Utils::HostToLittleEndian32(bit_cast<uint32_t>(value)));
|
| - } else {
|
| - value = bit_cast<float>(
|
| - Utils::HostToBigEndian32(bit_cast<uint32_t>(value)));
|
| - }
|
| - return Double::New(value);
|
| -}
|
| -
|
| -
|
| -DEFINE_NATIVE_ENTRY(ByteData_ToEndianFloat64, 2) {
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Double, host_value, arguments->NativeArgAt(0));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Bool, little_endian, arguments->NativeArgAt(1));
|
| - double value = host_value.value();
|
| - if (little_endian.value()) {
|
| - value = bit_cast<double>(
|
| - Utils::HostToLittleEndian64(bit_cast<uint64_t>(value)));
|
| - } else {
|
| - value = bit_cast<double>(
|
| - Utils::HostToBigEndian64(bit_cast<uint64_t>(value)));
|
| - }
|
| - return Double::New(value);
|
| -}
|
| -
|
| -} // namespace dart
|
|
|