Make ImmutableArray a sub class of AllStatic.
This enables Array to be a FINAL_HEAP_OBJECT and the operators
'=' and '^=' would be a simpler implementation which does not
require a call to initializeHandle().

R=iposva@google.com

Review URL: https://codereview.chromium.org//16390002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@23884 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 0afd8df..bf35ec2 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -2043,7 +2043,7 @@
   const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(list));
   // If the list is immutable we call into Dart for the indexed setter to
   // get the unsupported operation exception as the result.
-  if (obj.IsArray() && !obj.IsImmutableArray()) {
+  if (obj.IsArray() && !Array::Cast(obj).IsImmutable()) {
     SET_LIST_ELEMENT(isolate, Array, obj, index, value);
   } else if (obj.IsGrowableObjectArray()) {
     SET_LIST_ELEMENT(isolate, GrowableObjectArray, obj, index, value);
@@ -2297,7 +2297,7 @@
       return Api::NewError("Invalid length passed in to access list elements");
     }
   }
-  if (obj.IsArray() && !obj.IsImmutableArray()) {
+  if (obj.IsArray() && !Array::Cast(obj).IsImmutable()) {
     // If the list is immutable we call into Dart for the indexed setter to
     // get the unsupported operation exception as the result.
     SET_LIST_ELEMENT_AS_BYTES(isolate,
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index b5259dd..ced4460 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -530,7 +530,7 @@
   cls = Class::New<Array>();
   isolate->object_store()->set_array_class(cls);
   cls.set_type_arguments_field_offset(Array::type_arguments_offset());
-  cls = Class::New<ImmutableArray>();
+  cls = Class::New<Array>(kImmutableArrayCid);
   isolate->object_store()->set_immutable_array_class(cls);
   cls.set_type_arguments_field_offset(Array::type_arguments_offset());
   cls = Class::NewStringClass(kOneByteStringCid);
@@ -832,10 +832,11 @@
   RegisterPrivateClass(cls, Symbols::GrowableObjectArray(), core_lib);
   pending_classes.Add(cls, Heap::kOld);
 
-  cls = Class::New<ImmutableArray>();
+  cls = Class::New<Array>(kImmutableArrayCid);
   object_store->set_immutable_array_class(cls);
   cls.set_type_arguments_field_offset(Array::type_arguments_offset());
   ASSERT(object_store->immutable_array_class() != object_store->array_class());
+  cls.set_is_prefinalized();
   RegisterPrivateClass(cls, Symbols::ImmutableArray(), core_lib);
   pending_classes.Add(cls, Heap::kOld);
 
@@ -1120,7 +1121,7 @@
   cls = Class::New<Array>();
   object_store->set_array_class(cls);
 
-  cls = Class::New<ImmutableArray>();
+  cls = Class::New<Array>(kImmutableArrayCid);
   object_store->set_immutable_array_class(cls);
 
   cls = Class::New<GrowableObjectArray>();
@@ -12542,9 +12543,10 @@
 
 const char* Array::ToCString() const {
   if (IsNull()) {
-    return "Array NULL";
+    return IsImmutable() ? "ImmutableArray NULL" : "Array NULL";
   }
-  const char* format = "Array len:%"Pd"";
+  const char* format = !IsImmutable() ? "Array len:%"Pd"" :
+      "Immutable Array len:%"Pd"";
   intptr_t len = OS::SNPrint(NULL, 0, format, Length()) + 1;
   char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
   OS::SNPrint(chars, len, format, Length());
@@ -12612,18 +12614,6 @@
 }
 
 
-const char* ImmutableArray::ToCString() const {
-  if (IsNull()) {
-    return "ImmutableArray NULL";
-  }
-  const char* format = "ImmutableArray len:%"Pd"";
-  intptr_t len = OS::SNPrint(NULL, 0, format, Length()) + 1;
-  char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
-  OS::SNPrint(chars, len, format, Length());
-  return chars;
-}
-
-
 void GrowableObjectArray::Add(const Object& value, Heap::Space space) const {
   ASSERT(!IsNull());
   if (Length() == Capacity()) {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 149b390..35786cb 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -4932,6 +4932,10 @@
     StorePointer(ObjectAddr(index), value.raw());
   }
 
+  bool IsImmutable() const {
+    return raw()->GetClassId() == kImmutableArrayCid;
+  }
+
   virtual RawAbstractTypeArguments* GetTypeArguments() const {
     return raw_ptr()->type_arguments_;
   }
@@ -5005,19 +5009,38 @@
     raw_ptr()->length_ = Smi::New(value);
   }
 
-  HEAP_OBJECT_IMPLEMENTATION(Array, Instance);
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(Array, Instance);
   friend class Class;
+  friend class ImmutableArray;
   friend class Object;
   friend class String;
 };
 
 
-class ImmutableArray : public Array {
+class ImmutableArray : public AllStatic {
  public:
   static RawImmutableArray* New(intptr_t len, Heap::Space space = Heap::kNew);
 
+  static RawImmutableArray* ReadFrom(SnapshotReader* reader,
+                                     intptr_t object_id,
+                                     intptr_t tags,
+                                     Snapshot::Kind kind);
+
+  static const ClassId kClassId = kImmutableArrayCid;
+
+  static intptr_t InstanceSize() {
+    return Array::InstanceSize();
+  }
+
+  static intptr_t InstanceSize(intptr_t len) {
+    return Array::InstanceSize(len);
+  }
+
  private:
-  FINAL_HEAP_OBJECT_IMPLEMENTATION(ImmutableArray, Array);
+  static RawImmutableArray* raw(const Array& array) {
+    return reinterpret_cast<RawImmutableArray*>(array.raw());
+  }
+
   friend class Class;
 };
 
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 0d57f54..4a51160 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -211,7 +211,7 @@
   if (class_id < kNumPredefinedCids) {
     switch (class_id) {
 #define RAW_VISITPOINTERS(clazz)                                               \
-      case clazz::kClassId: {                                                  \
+      case k##clazz##Cid: {                                                    \
         Raw##clazz* raw_obj = reinterpret_cast<Raw##clazz*>(this);             \
         size = Raw##clazz::Visit##clazz##Pointers(raw_obj, visitor);           \
         break;                                                                 \
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index fab5eec..1ef30f4 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -13,7 +13,7 @@
 namespace dart {
 
 // Macrobatics to define the Object hierarchy of VM implementation classes.
-#define CLASS_LIST_NO_OBJECT_OR_STRING(V)                                      \
+#define CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY(V)                           \
   V(Class)                                                                     \
   V(UnresolvedClass)                                                           \
   V(AbstractTypeArguments)                                                     \
@@ -60,8 +60,6 @@
         V(Bigint)                                                              \
       V(Double)                                                                \
     V(Bool)                                                                    \
-    V(Array)                                                                   \
-      V(ImmutableArray)                                                        \
     V(GrowableObjectArray)                                                     \
     V(TypedData)                                                               \
     V(ExternalTypedData)                                                       \
@@ -72,6 +70,9 @@
     V(Float32x4)                                                               \
     V(Uint32x4)                                                                \
 
+#define CLASS_LIST_ARRAYS(V)                                                   \
+  V(Array)                                                                     \
+    V(ImmutableArray)                                                          \
 
 #define CLASS_LIST_STRINGS(V)                                                  \
   V(String)                                                                    \
@@ -95,11 +96,13 @@
   V(Float32x4Array)                                                            \
 
 #define CLASS_LIST_FOR_HANDLES(V)                                              \
-  CLASS_LIST_NO_OBJECT_OR_STRING(V)                                            \
+  CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY(V)                                 \
+  V(Array)                                                                     \
   V(String)
 
 #define CLASS_LIST_NO_OBJECT(V)                                                \
-  CLASS_LIST_NO_OBJECT_OR_STRING(V)                                            \
+  CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY(V)                                 \
+  CLASS_LIST_ARRAYS(V)                                                         \
   CLASS_LIST_STRINGS(V)
 
 #define CLASS_LIST(V)                                                          \
@@ -1602,9 +1605,9 @@
 inline bool RawObject::IsBuiltinListClassId(intptr_t index) {
   // Make sure this function is updated when new builtin List types are added.
   ASSERT(kImmutableArrayCid == kArrayCid + 1 &&
-         kGrowableObjectArrayCid == kArrayCid + 2 &&
-         kTypedDataCid == kArrayCid + 3);
-  return ((index >= kArrayCid && index < kTypedDataCid) ||
+         kTypedDataCid == kGrowableObjectArrayCid + 1);
+  return ((index >= kArrayCid && index < kImmutableArrayCid) ||
+          (index >= kGrowableObjectArrayCid && index < kTypedDataCid) ||
           IsTypedDataClassId(index) ||
           IsTypedDataViewClassId(index) ||
           IsExternalTypedDataClassId(index));
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index cd4e0e5..d4f39a7 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -2082,16 +2082,15 @@
 
   // Read the length so that we can determine instance size to allocate.
   intptr_t len = reader->ReadSmiValue();
-  ImmutableArray* array = reinterpret_cast<ImmutableArray*>(
-      reader->GetBackRef(object_id));
+  Array* array = reinterpret_cast<Array*>(reader->GetBackRef(object_id));
   if (array == NULL) {
-    array = &(ImmutableArray::ZoneHandle(
+    array = &(Array::ZoneHandle(
         reader->isolate(),
         NEW_OBJECT_WITH_LEN_SPACE(ImmutableArray, len, kind)));
     reader->AddBackRef(object_id, array, kIsDeserialized);
   }
   reader->ArrayReadFrom(*array, len, tags);
-  return array->raw();
+  return raw(*array);
 }
 
 
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index c94965d..ff22e03 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -33,6 +33,8 @@
   // Check if this is a class which is stored in the object store.
   return (class_id == kObjectCid ||
           (class_id >= kInstanceCid && class_id <= kWeakPropertyCid) ||
+          class_id == kArrayCid ||
+          class_id == kImmutableArrayCid ||
           RawObject::IsStringClassId(class_id) ||
           RawObject::IsTypedDataClassId(class_id) ||
           RawObject::IsExternalTypedDataClassId(class_id));
@@ -296,7 +298,7 @@
   if (class_id == kImmutableArrayCid) {
     // Read the length and allocate an object based on the len.
     intptr_t len = ReadSmiValue();
-    ImmutableArray& array = ImmutableArray::ZoneHandle(
+    Array& array = Array::ZoneHandle(
         isolate(),
         (kind_ == Snapshot::kFull) ?
         NewImmutableArray(len) : ImmutableArray::New(len, HEAP_SPACE(kind_)));