| Index: runtime/vm/object.cc
|
| ===================================================================
|
| --- runtime/vm/object.cc (revision 38576)
|
| +++ runtime/vm/object.cc (working copy)
|
| @@ -1155,6 +1155,27 @@
|
| cls = Class::New<MirrorReference>();
|
| RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib);
|
|
|
| + // Pre-register the collection library so we can place the vm class
|
| + // LinkedHashMap there rather than the core library.
|
| + lib = Library::LookupLibrary(Symbols::DartCollection());
|
| + if (lib.IsNull()) {
|
| + lib = Library::NewLibraryHelper(Symbols::DartCollection(), true);
|
| + lib.SetLoadRequested();
|
| + lib.Register();
|
| + isolate->object_store()->set_bootstrap_library(ObjectStore::kCollection,
|
| + lib);
|
| + }
|
| + ASSERT(!lib.IsNull());
|
| + ASSERT(lib.raw() == Library::CollectionLibrary());
|
| +
|
| + cls = Class::New<LinkedHashMap>();
|
| + object_store->set_linked_hash_map_class(cls);
|
| + cls.set_type_arguments_field_offset(LinkedHashMap::type_arguments_offset());
|
| + cls.set_num_type_arguments(2);
|
| + cls.set_num_own_type_arguments(2);
|
| + RegisterPrivateClass(cls, Symbols::_LinkedHashMap(), lib);
|
| + pending_classes.Add(cls);
|
| +
|
| // Pre-register the profiler library so we can place the vm class
|
| // UserTag there rather than the core library.
|
| lib = Library::LookupLibrary(Symbols::DartProfiler());
|
| @@ -1433,6 +1454,9 @@
|
| cls = Class::New<GrowableObjectArray>();
|
| object_store->set_growable_object_array_class(cls);
|
|
|
| + cls = Class::New<LinkedHashMap>();
|
| + object_store->set_linked_hash_map_class(cls);
|
| +
|
| cls = Class::New<Float32x4>();
|
| object_store->set_float32x4_class(cls);
|
|
|
| @@ -18099,6 +18123,170 @@
|
| }
|
|
|
|
|
| +// Equivalent to Dart's operator "==" and hashCode.
|
| +class DefaultHashTraits {
|
| + public:
|
| + static bool IsMatch(const Object& a, const Object& b) {
|
| + if (a.IsNull() || b.IsNull()) {
|
| + return (a.IsNull() && b.IsNull());
|
| + } else {
|
| + return Instance::Cast(a).OperatorEquals(Instance::Cast(b));
|
| + }
|
| + }
|
| + static uword Hash(const Object& obj) {
|
| + if (obj.IsNull()) {
|
| + return 0;
|
| + }
|
| + // TODO(koda): Ensure VM classes only produce Smi hash codes, and remove
|
| + // non-Smi cases once Dart-side implementation is complete.
|
| + Isolate* isolate = Isolate::Current();
|
| + REUSABLE_INSTANCE_HANDLESCOPE(isolate);
|
| + Instance& hash_code = isolate->InstanceHandle();
|
| + hash_code ^= Instance::Cast(obj).HashCode();
|
| + if (hash_code.IsSmi()) {
|
| + // May waste some bits on 64-bit, to ensure consistency with non-Smi case.
|
| + return static_cast<uword>(Smi::Cast(hash_code).Value() & 0xFFFFFFFF);
|
| + } else if (hash_code.IsInteger()) {
|
| + return static_cast<uword>(
|
| + Integer::Cast(hash_code).AsTruncatedUint32Value());
|
| + } else {
|
| + return 0;
|
| + }
|
| + }
|
| +};
|
| +typedef EnumIndexHashMap<DefaultHashTraits> EnumIndexDefaultMap;
|
| +
|
| +
|
| +intptr_t LinkedHashMap::Length() const {
|
| + EnumIndexDefaultMap map(Array::Handle(data()));
|
| + intptr_t result = map.NumOccupied();
|
| + {
|
| + RawArray* array = map.Release();
|
| + ASSERT(array == data());
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| +void LinkedHashMap::InsertOrUpdate(const Object& key,
|
| + const Object& value) const {
|
| + ASSERT(!IsNull());
|
| + EnumIndexDefaultMap map(Array::Handle(data()));
|
| + if (!map.UpdateOrInsert(key, value)) {
|
| + SetModified();
|
| + }
|
| + StorePointer(&raw_ptr()->data_, map.Release());
|
| +}
|
| +
|
| +
|
| +RawObject* LinkedHashMap::LookUp(const Object& key) const {
|
| + ASSERT(!IsNull());
|
| + EnumIndexDefaultMap map(Array::Handle(data()));
|
| + const Object& result = Object::Handle(map.GetOrNull(key));
|
| + {
|
| + RawArray* array = map.Release();
|
| + ASSERT(array == data());
|
| + }
|
| + return result.raw();
|
| +}
|
| +
|
| +
|
| +bool LinkedHashMap::Contains(const Object& key) const {
|
| + ASSERT(!IsNull());
|
| + EnumIndexDefaultMap map(Array::Handle(data()));
|
| + bool result = map.ContainsKey(key);
|
| + {
|
| + RawArray* array = map.Release();
|
| + ASSERT(array == data());
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| +RawObject* LinkedHashMap::Remove(const Object& key) const {
|
| + ASSERT(!IsNull());
|
| + EnumIndexDefaultMap map(Array::Handle(data()));
|
| + // TODO(koda): Make 'Remove' also return the old value.
|
| + const Object& result = Object::Handle(map.GetOrNull(key));
|
| + if (map.Remove(key)) {
|
| + SetModified();
|
| + }
|
| + StorePointer(&raw_ptr()->data_, map.Release());
|
| + return result.raw();
|
| +}
|
| +
|
| +
|
| +void LinkedHashMap::Clear() const {
|
| + ASSERT(!IsNull());
|
| + if (Length() != 0) {
|
| + EnumIndexDefaultMap map(Array::Handle(data()));
|
| + map.Initialize();
|
| + SetModified();
|
| + StorePointer(&raw_ptr()->data_, map.Release());
|
| + }
|
| +}
|
| +
|
| +
|
| +RawArray* LinkedHashMap::ToArray() const {
|
| + EnumIndexDefaultMap map(Array::Handle(data()));
|
| + const Array& result = Array::Handle(HashTables::ToArray(map, true));
|
| + RawArray* array = map.Release();
|
| + ASSERT(array == data());
|
| + return result.raw();
|
| +}
|
| +
|
| +
|
| +void LinkedHashMap::SetModified() const {
|
| + StorePointer(&raw_ptr()->cme_mark_, Instance::null());
|
| +}
|
| +
|
| +
|
| +RawInstance* LinkedHashMap::GetModificationMark(bool create) const {
|
| + if (create && raw_ptr()->cme_mark_ == Instance::null()) {
|
| + Isolate* isolate = Isolate::Current();
|
| + const Class& object_class =
|
| + Class::Handle(isolate, isolate->object_store()->object_class());
|
| + const Instance& current =
|
| + Instance::Handle(isolate, Instance::New(object_class));
|
| + StorePointer(&raw_ptr()->cme_mark_, current.raw());
|
| + }
|
| + return raw_ptr()->cme_mark_;
|
| +}
|
| +
|
| +
|
| +RawLinkedHashMap* LinkedHashMap::New(Heap::Space space) {
|
| + ASSERT(Isolate::Current()->object_store()->linked_hash_map_class()
|
| + != Class::null());
|
| + static const intptr_t kInitialCapacity = 4;
|
| + const Array& data =
|
| + Array::Handle(HashTables::New<EnumIndexDefaultMap>(kInitialCapacity,
|
| + space));
|
| + LinkedHashMap& result = LinkedHashMap::Handle();
|
| + {
|
| + RawObject* raw = Object::Allocate(LinkedHashMap::kClassId,
|
| + LinkedHashMap::InstanceSize(),
|
| + space);
|
| + NoGCScope no_gc;
|
| + result ^= raw;
|
| + result.SetData(data);
|
| + result.SetModified();
|
| + }
|
| + return result.raw();
|
| +}
|
| +
|
| +
|
| +const char* LinkedHashMap::ToCString() const {
|
| + // TODO(koda): Print key/value pairs.
|
| + return "_LinkedHashMap";
|
| +}
|
| +
|
| +
|
| +void LinkedHashMap::PrintJSONImpl(JSONStream* stream, bool ref) const {
|
| + // TODO(koda): Print key/value pairs.
|
| + Instance::PrintJSONImpl(stream, ref);
|
| +}
|
| +
|
| +
|
| RawFloat32x4* Float32x4::New(float v0, float v1, float v2, float v3,
|
| Heap::Space space) {
|
| ASSERT(Isolate::Current()->object_store()->float32x4_class() !=
|
|
|